Help us understand the problem. What is going on with this article?

Javascriptを1行で書く

More than 1 year has passed since last update.

私は普段、色々な処理をJavascript1行で書くことを趣味にしていて、過去いろいろな処理を1行で書いています。
通称「JSシェル芸」「Javascriptシェル芸」などのアダ名で呼ばれています。
最初に披露したのが第28回基準値を超えるシェル芸勉強会で、そこで好評だったために細々と続けています。
最近はシェル芸勉強会以外にも、Javascript関連の勉強会などのLTでやったりして、そこそこウケたり、ドン引きされたりしています。
他に書いている人がおらず、『どうやって作成しているのですか?』という質問をもらったりすることもあり、今回は私の作成の仕方をまとめたいと思います。

作成例

素数の算出

console.log(((num = 60, f = (arr, i) => arr[i] > Math.sqrt(num) ? arr : f(arr.filter((v) => v === arr[i] || v % arr[i] !== 0), ++i)) => f([...Array(num)].map((v,i) => i+1).slice(1), 0)).call())

sin波を書く

[...Array(20)].map((u, i) => Math.round((Math.sin(i) + 1) * 4)).forEach((count) => console.log(`${ " ".repeat(count) }*`))

シェルピンスキーのギャスケット
sierpinski_gasket.gif

https://github.com/butackle/JavascriptOneLiner/blob/master/monsterLine/sierpinski_gasket.js

マイルール

セミコロンを使わず全て繋げて書くというのが大原則です。
セミコロンを使うと、ただの圧縮になってしまうので・・・。
あと最近は、{}も使わずに書くようにしています。アロー関数を繋げまくります。
実行環境は特に決めていません。
ブラウザのコンソールを使う時もあれば、ファイル読込とかが必要な際にはNode.jsを使ったりしますし、図を描画したい時には下記のHTMLファイルを使う時もあります。

canvas.html
<canvas id=canvas width="2000px" height="2000px"></canvas>

<html>とか<head>とかはもう面倒なので省いています。

作成の仕方

慣れてくると、徐々に最初から1行では書けるようにはなるのですが、
悩む場合は、最初から繋げて書いたりはしません。
部品ごとに作っていきます。

/*
響け!ユーフォニアム
け!ユーフォニアム響
!ユーフォニアム響け
ユーフォニアム響け!
ーフォニアム響け!ユ
フォニアム響け!ユー
ォニアム響け!ユーフ
ニアム響け!ユーフォ
アム響け!ユーフォニ
厶響け!ユーフォニア
*/

const splitEuphonium = "響け!ユーフォニアム".split("");
const makeLine = (char, index, line) => line.map((str, i, a) => a[Math.abs(i - index)]).join('');
const makeSentence = splitEuphonium.map(makeLine).join('\n')
console.log(makeSentence)

上記の例はシェル芸の王道である響け!ユーフォニアムの回答の一例です。 1行回答としてはconsole.log("響け!ユーフォニアム".split("").map((char, index, line) => line.map((str, i, a) => a[Math.abs(i - index)]).join('')).join('\n'))としていますが、考える過程で
・splitEuphonium → 文字列を分割する処理
・makeLine → 行を作成
・makeSentence → 文章を作成
というように必要な処理を細分化して書いて、そのあとに結合します。
このようにすると、デバッグも楽です。
繋げてからのデバッグは大変だと思います。

制御フロー文を再現してみる

if文

if(Date.now() % 3 === 0) {
    console.log("1");
} else if (Date.now() % 2 === 0) {
    console.log("2");
} else {
    console.log("3");
}
//
// ↑ 同じ出力をする ↓
//
console.log(Date.now() % 3 === 0 ? "1" : Date.now() % 2 === 0 ? "2" : "3")

三項演算子を使います。

for文

for(i=0; i<2; ++i){
    console.log(i);
}
//
// ↑ 同じ出力をする ↓
//
[...Array(2)].forEach((v,i) => console.log(i))

[...Array(2)]で要素数が2の配列を生成しています。

do-while文

i = 0;
do{
    console.log(i++);
}while(i <= 10)
//
// ↑ 同じ出力をする ↓
//
((f = (i) => console.log(i) || i < 10 ? f(++i) : undefined) => f(0)).call()

console.log(i)は必ずundefinedが返るのでfalseとして判定されます。
そうすると必ず次のi<10以降の三項演算子の処理は行われます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_Operators

作成に使うことが多いメソッド

処理を繋げていくに当たって、通常は配列または文字列を繋いでいくのが基本形です。

Array.prototype.map()

もっとも基本の処理です。この関数を用いて、値を変えながら作成していくことがポピュラーなやり方です。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

Array.prototype.reduce()

いろいろと応用が効き便利です。配列からオブジェクト・文字列を作成することも出来ます。
ただreduceの中でreduceを入れると、結構自分の頭で追うのが大変です。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

Array.prototype.join()
String.prototype.split()

配列から文字列を生成したり、文字列を分割したりして、処理を繋げていきます。
他の方法で出来る場合もありますが、こちらは可読性が高いので、初めての方にはオススメです。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/join
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/split

String.prototype.replace()

パターンマッチに正規表現・変換に関数を使うことにより、かなり色々なことが出来ます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace

最後に

私自身は、特にJSに詳しいとかいう人間でもなく、今まで書いた事柄は、自分で処理を書きながらMozillaを読んだり試してみたりして把握していったものが大半です。
なるべく誤解や間違いが無いよう書いたつもりですが、もし間違い等ありましたら指摘していただけると嬉しいです。

過去の作成物など

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away