JavaScript ショートコードテクニック集（ES6含む）

何の役に立つかはわからない、ショートコードのテクニック集です。
ここで紹介しているテクニックの幾つかは非推奨の記述法です。
用法、用量を守って正しくお使いください。

# 基本

## 改行と半角スペースをなくす。

```javascript:before
var a = 1,
	b = 2;
console.log( a, b );
```

```javascript:after
var a=1,b=2;console.log(a,b);
```

varとaの間の半角スペースなど、なくすと意味が変わってしまう部分は取れない。

## 変数宣言（var）を省略し、変数の値が同じ場合まとめる

```javascript:before
var a = 1,
	b = 1;
```

```javascript:after
a=b=2;
```

#値や計算の省略

## 小数点の省略

```javascript:before
console.log(1+0.5);
```

```javascript:after
console.log(1+.5);
```

```javascript:console.log
1.5
```


## 下三桁以上が0の場合指数で表現

```javascript:before
console.log(1000);
```

```javascript:after
console.log(1e3);
```

```javascript:console.log
1000
```

三桁以上でないと効果なし。
例えば、1日をミリ秒に直すと`86400000`だが、これは`864e5`と表記すれば3文字節約できる。
また小数点の場合、四桁から効果がある。

```javascript
console.log(0.0001); // 6文字
console.log(.0001);  // 5文字
console.log(1e-4);   // 4文字
```

```javascript:console.log
0.0001
```

## 小数点の切捨てはビット演算で行う

```javascript:before
console.log(Math.floor(1.2345));
```

```javascript:after
console.log(1.2345|0);
```

```javascript:after
console.log(~~1.2345);
```

```javascript:console.log
1
```

## 四捨五入もビット演算で行う

```javascript:after
a=Math.round(10.3);
b=Math.round(10.6);
console.log(a,b);
```

```javascript:after
a=10.3+.5|0;
b=10.6+.5|0;
console.log(a,b);
```

```javascript:console.log
 10 11
```

0.5を足してビット演算をすれば四捨五入した整数値を得られる。

## べき乗をべき乗演算子で行う（ES6）

```javascript:before
console.log(Math.pow(-3,2));
```

```javascript:after
console.log(-3**2);
```

```javascript:console.log
9
```

べき乗演算子`**`が実装されたのでMath.powを使うより断然短くなる。

## 2の階乗をビットシフトで行う

```javascript:before
console.log(131072);
```

```javascript:after
console.log(1<<17);
```

```javascript:console.log
131072
```

2の17乗以上でないと効果なし。

## -1判定をビット演算で行う

例えばindexOfメソッドで条件判定を行うとき、下記のように−1と比較することになるが

```javascript:before
z='abcdefg';
if(z.indexOf('a')!==-1){
  console.log('a in z');
} else {
  console.log('a not in z');
}
// 'a in z'
```

ビット指定演算子`~`で−1のみを`false`判定にすることができる

```javascript:after
z='abcdefg';
if(~z.indexOf('a')){
  console.log('a in z');
} else {
  console.log('a not in z');
}
// 'a in z'
```

これは`-1`が`0`のビット反転（符号を含めて1で埋まっている状態）だからで、条件式では0以外の数値型が（負数も含めて）全て`true`判定になるからである。

逆に−1のみをtrueにしたい場合は`!~z.indexOf('a')`などにする。
−1を返すメソッドとして、indexOfの他にlastIndexOf、search、findIndexなどがある。

## 文字列型から数値型への変換

```javascript:before
var a = '123456';
parseInt(a) // 11文字
Number(a) // 9文字
```

```javascript:after
var a = '123456';
+a // 2文字
```

## 数値型から文字列型への変換

```javascript:before
var a = 123456;
a.toString() // 12文字
String(a) // 9文字
```

```javascript:after
var a = '123456';
a+'' // 4文字
```

## ゼロパディング

桁の合わない数字のゼロパディング（少ない桁を'0'で埋める）を行う場合、
望む桁数から1引いた数の'0'文字列（例えば、3桁を得たい場合`'00'`）を数字の頭に足し、
`slice()`を使って末尾からトリミングする方法が取れます。

```javascript
a=1;
a=('00'+a).slice(-3);
console.log(a);
```

```javascript:console.log
'001'
```

ただし、2桁を得る場合のみ、三項演算子が一番短くなります。

```javascript:2桁のゼロパディング
a=1;

// if文の場合、15文字
if(a<10)a='0'+a;

// 三項演算子の場合、14文字
a=a<10?'0'+a:a;

// sliceの場合、19文字
a=('0'+a).slice(-2);
```

```javascript:3桁のゼロパディング
a=1;

// 三項演算子の場合、27文字
a=a<10?'00'+a:a<100?'0'+a:a;

// sliceの場合、20文字
a=('00'+a).slice(-3);
```

さらにES2017ではパディング用のメソッド`padStart()`が用意されていますが、ショートコード観点で言うと6桁以上でないと効果がありません。

```javascript:6桁のゼロパディング
a=1;

// sliceの場合、23文字
a=('00000'+a).slice(-6);

// padStartの場合、22文字
a=(''+a).padStart(6,0);
```

また、年月日、時分秒などの数字混じり文字列に対するゼロパディングについては`replace()`で行う方法があります。

```javascript
a='2017/4/5';
a=a.replace(/(\D)(\d)(?=\D|$)/g,"$10$2");
console.log(a)
```

```javascript:console.log
"2017/04/05"
```

置換処理の部分については3桁以上の場合は後方参照ではなく関数で処理した方が短くなります。

## true/falseを!0/!1で代用する

```javascript:before
console.log(true,false);
```

```javascript:after
console.log(!0,!1);
```

```javascript:console.log
 true false
```

論理否定演算子（!）が後に続く0や1を評価するため、結果としてtrue,falseが得られます。

## 配列型のように文字列から一文字を抜き出す。

```javascript:before
console.log('あいうえお'.charAt(2));
```

```javascript:after
console.log('あいうえお'[2]);
```

```javascript:console.log
'う'
```

## 文字列を配列化する場合、区切り文字に数字を使う。

```javascript:before
var a='abc,def,ghi,jkl,mno';
console.log(a.split(','));
```

```javascript:after
var a='abc0def0ghi0jkl0mno';
console.log(a.split(0));
```

```javascript:console.log
 ["abc", "def", "ghi", "jkl", "mno"]
```

この方法は配列のショートコード化にも利用でき、

```javascript:before
a=['aa','bb','cc','dd','ee'];
console.log(a)
```

```javascript:after
a='aa0bb0cc0dd0ee'.split(0);
console.log(a)
```

```javascript:console.log
["a", "b", "c", "d", "e"]
```

5個以上の文字列の配列であれば、一つの文字列をsplitで分けたほうが文字数を削減できます。

また、文字列を一文字ずつ配列に格納したい場合、

```javascript:before
a='abcdefg'.split('');
console.log(a);
```

```javascript:before
a=[...'abcdefg'];
console.log(a);
```

```javascript:console.log
[ "a", "b", "c", "d", "e", "f", "g" ]
```

es6のスプレッド構文ならばsplitメソッドを使うより、文字数を削減できます。

## 同じ文字の繰り返しを作る場合、repeat()を使う。（ES6）

```javascript:before
console.log('aaaaaaaaaaaaaa');
```

```javascript:after
console.log('a'.repeat(13));
```

```javascript:console.log
'aaaaaaaaaaaaaa'
```

n回の繰り返し文字列を得たい場合、repeat()を使う。13文字以上でないと効果なし。
ただしrepeat()は現在Firefoxのみ対応なので、

```javascript:after
console.log(Array(17).join`a`);
```

n+1の配列を作り繰り返したい文字列でjoinする方法を使う。
この方法は16文字以上でないと効果なし。

また、配列のままで良い場合はfill()メソッドが使える。（ES6）

```javascript:after
console.log(Array(17).fill('a'));
```



## 乱数生成にDateを利用する

```javascript:before
console.log(Math.random()*2&1);
```

```javascript:after
console.log(new Date&1);
```

```javascript:console.log
// 0か1の乱数を生成する
```

ミリ秒を返すDateは乱数の代わりとして利用できる。

## 配列の値の取り出しに分割代入を使う（ES6）

```javascript:before
a=0;
b=0;
c=[1,[2,3,4],5];
a=c[0];
b=c[1][0];
console.log(a,b);
```

```javascript:after
a=0;
b=0;
c=[1,[2,3,4],5];
[a]=c;
[,[b]]=c;
console.log(a,b);
```

```javascript:console.log
1 2
```

配列の0番目へのアクセスに分割代入を利用すれば（１文字分だけだが）ショートコード化することができる。
これは文字列に対しても有効。

```javascript:after
a='';
b='xyz';
[a]=b;
console.log(a);
// -> 'x'
```

## 配列のコピーにスプレッド構文を使う（ES6）

```javascript:before
a=[1, 2, 3];
b=a.slice(); // 11文字
b.push(4);
console.log(a, b);
```

```javascript:after
a=[1, 2, 3];
[...b]=a; // 8文字
b.push(4);
console.log(a, b);
```

```javascript:console.log
[ 1, 2, 3 ] [ 1, 2, 3, 4 ]
```

スプレッド演算子を使えばslice()を使うより短く配列コピーを実現できます。

## 配列やオブジェクトの連結にスプレッド構文を使う（ES6）

```javascript:before
a=[1,2,3],b=[4,5,6];
a.push.apply(a,b);
console.log(a);
```

```javascript:after
a=[1,2,3],b=[4,5,6];
a.push(...b);
console.log(a);
```

```javascript:after
a=[1,2,3],b=[4,5,6];
console.log([...a,...b]);
```

```javascript:console.log
[1, 2, 3, 4, 5, 6]
```

スプレッド構文を使えば配列やオブジェクトを分割して代入できます。
また同じ方法でオブジェクトのマージも可能です。

```javascript:before
a={z1:1,z2:2,z3:3}
b={z2:4,z3:5,z4:6}
c=Object.assign(a,b) // 18文字
console.log(c)
```

```javascript:after
a={z1:1,z2:2,z3:3}
b={z2:4,z3:5,z4:6}
c={...a,...b} // 11文字
console.log(c)
```

```javascript:console.log
{ z1: 1, z2: 4, z3: 5, z4: 6 }
```

## 配列の先頭を削る（ES6）

```javascript:before
a=[1,2,3,4,5,6];
b=a.slice(1);
console.log(b);
```

```javascript:after
a=[1,2,3,4,5,6];
[,...b]=a;
console.log(b);
```

```javascript:console.log
[2, 3, 4, 5, 6]
```

スプレッド構文を使ってbを可変長にすることで配列の先頭を削った配列を返します（カンマを繰り返して複数削ることも可能）。ただしこの方法は後尾から配列を削る応用はできません。

## 16進数文字列の10進数化の省略

```javascript:before
a='10';
console.log(parseInt('10',16));
```

```javascript:after
a='10';
console.log('0x'+a-0);
```

```javascript:console.log
16
```

最後に数値型0を計算することで全体を数値型に変換し、結果として10進数になります。
また2進数なら「0b」、8進数なら「0o」で変換できます。

## 配列数の評価にlengthプロパティではなくin演算子を使う
```javascript:before
a=[1,2,3];
console.log(a.length>3); // 10文字
```

```javascript:after
a=[1,2,3];
console.log(3 in a); // 6文字
```

```javascript:console.log
false
```
Arrayオブジェクトの場合in演算子によってインデックスが存在するかを検査でき、lengthプロパティを使うより文字数を少なくできる。

文字列の場合はin演算子を使えないが（文字列オブジェクトにすれば別）、直接アクセスすることでlengthを使わない方法で文字数を評価できる。

```javascript:before
a='xyz';
console.log(a.length>3); // 10文字
```

```javascript:after
a='xyz';
console.log(!!a[3]); // 6文字
```

```javascript:console.log
false
```

#オブジェクトやメソッドなどの省略

## window オブジェクトをthisで取得

```javascript:before
console.log(window);
```

```javascript:after
console.log(this);
```

```javascript:console.log
Window
```

グローバルにおける`this`はwindowオブジェクトを示す（Node.jsにおいてはglobal）ので、thisに変えれば２文字省略できる。

## document.getElementByIdの省略

```html:html
<div id="t">this is test.</div>
```

```javascript:before
console.log(document.getElementById('t').innerText);
```

```javascript:after
console.log(t.innerText);
```

```javascript:console.log
"this is test."
```

HTMLに指定したidはオブジェクトとして直接指定することができる。
`document.body`なども、bodyタグにidを指定することができれば、直接指定できる。

## new演算子の対象のカッコを省略する

```javascript:before
console.log(new Date());
console.log(new Array());
```

```javascript:after
console.log(new Date);
console.log(new Array);
```

```javascript:console.log
//現在時刻
[]
```

new演算子の対象とするオブジェクトの場合、カッコ()を省略することができる。


## 繰り返し使うメソッドやオブジェクトを変数に格納する。

```javascript:before
console.log(Math.ceil(12.5),Math.ceil(0.2));
```

```javascript:after
a=Math.ceil;
console.log(a(12.5),a(0.2));
```

```javascript:console.log
13 1
```

## 頻出するオブジェクトをwith句でまとめる

```javascript:before
Math.ceil(1.5)+Math.floor(1.5)+Math.round(1.5);
```

```javascript:after
with(Math)ceil(1.5)+floor(1.5)+round(1.5);
```

```javascript:console.log
5
```

## メソッドに配列でアクセスする

```javascript:before
test1.classList.add('a');
test2.classList.remove('b');
test3.classList.add('c');
```

```javascript:after
test1[x='classList'][y='add']('a');
test2[x].remove('b');
test3[x][y]('c');
```

```javascript:console.log
// それぞれの要素のクラスを付加ないし削除する
```


## setTimeout、setIntervalの第一引数を文字列で渡す
```javascript:before
setTimeout(function(){
	console.log('あ');
},1000);
```

```javascript:after
setTimeout("console.log('あ')",1000);
```

```javascript:console.log
'あ'
```

setTimeout、setIntervalはeval()のように文字列をコードとして評価することができる（evalと同じく非推奨）。さらに時間が1ミリ秒であれば第二引数を省略できる。

```javascript:after
setTimeout("console.log('あ')");
```

ES6ならさらに省略できる

```javascript:after
setTimeout`console.log('あ')`;
```

## 文字列を渡すメソッドや関数の()を省略する（ES6）
```javascript:before
alert('あ'); // アラートボックスを表示する
test.classList.add('a'); // test要素にクラス名「ａ」を追加する
```

```javascript:after
alert`あ`;
test.classList.add`a`
```

クォーテーションではなくバックティック（\` \`）で渡すことでパーレンを省略できる。
これはテンプレートリテラルを直接関数やメソッドに渡すと、第一引数として、文字列を返すことを利用したもの（したがって第2引数まで利用するような処理の場合はエラーが発生する恐れがある）。

#ステートメントの省略

## if文の省略

### else節の無いif文を論理演算子で代用する

```javascript:before
a='あ';
if(a=='あ'){
	console.log(a+a);
}
```

```javascript:after
a='あ';
(a=='あ')&&console.log(a+a);
```

```javascript:console.log
'ああ'
```

AND(&&)は左辺がtrueの場合右辺を評価し、左辺がfalseの場合右辺を評価しないのでif文の代用として使用できる。

```javascript:before
a=0;
if(!a){
	console.log(a);
}
```

```javascript:after
a=0;
a||console.log(a);
```

```javascript:console.log
0
```

条件に否定演算子を使っている場合はOR(||)を使います。||は左辺がtrueの場合右辺を評価せず、左辺がfalseの場合右辺を評価します。

### if...else文を三項演算子に書き換える。

```javascript:before
var a=1,b=2,c;
if(a==1){
	c=a+b;
} else {
	c=a-b;
}
console.log(c);
```

```javascript:after
var a=1,b=2,c;
c=(a==1)?a+b:a-b;
console.log(c);
```

```javascript:console.log
3
```

「条件?処理:条件?処理:処理」のように書けば、else ifも表現することができる。

## 型の判定

### string型

```javascript:before
a=0;
b='0';
// 19文字
console.log(typeof a==='string'); // false
console.log(typeof b==='string'); // true
```

```javascript:after
a=0;
b='0';
// 8文字
console.log(''+a===a); // false
console.log(''+b===b); // true
// 5文字
console.log(a.big); // undefined
console.log(b.big); // function big()
```

`''+a===a`の方法は強制的に文字列化して、元の変数と比べることでString型かどうかを判定している。
`a.big`はString型固有のメソッドであるbig()メソッドが有効であるかを調べることで判定している。
※big()メソッドは現在非推奨であり、いつ使えなくなるかはブラウザ次第。

### number型

```javascript:before
a=0;
b='0';
console.log(typeof a==='number');
console.log(typeof b==='number'); // 19文字
```

```javascript:after
a=0;
b='0';
console.log(+a===a);
console.log(+b===b); // 6文字
```

```javascript:console.log
true
false
```

### boolean型

```javascript:before
a=0;
b=false;
console.log(typeof a==='boolean');
console.log(typeof b==='boolean'); // 19文字
```

```javascript:after
a=0;
b=false;
console.log(!!a===a);
console.log(!!b===b); // 7文字
```

```javascript:console.log
false
true
```

### undefined

```javascript:before
a={b:3};
console.log(typeof a.b==='undefined');
console.log(typeof a.c==='undefined');  // 24文字
```

```javascript:after
a={b:3};
console.log(a.b===0[0]);
console.log(a.c===0[0]); // 10文字
```

```javascript:console.log
false
true
```

undefinedはundefinedになる文と比較することでtypeofの代替になる。




### Infinity

```javascript:before
a=0;
b=Math.pow(10, 1000);;
// 11文字
console.log(isFinite(a)); // true
// 12文字
console.log(!isFinite(b)); // true
// 12文字
console.log(a!==Infinity); // true
// 12文字
console.log(b===Infinity); // true
```

```javascript:after
a=0;
b=Math.pow(10, 1000);;
// 7文字
console.log(a!==1/0); // true
// 7文字
console.log(b===1/0); // true
```

計算結果が無限大になる計算はInfinity変数と同値となるので、結果無限大の判定に利用できる。

### function型
```javascript:before
b=()=>3;
// 21文字
console.log(typeof b==='function');  // true
```

```javascript:after
b=()=>3;
// 19文字
console.log(/^f/.test(typeof b)); // true
// 5文字
console.log(b.call); // function call()
```

functionは単純に比較できないので、typeofの結果の1文字目を判定する。
`b.call`はfunctionオブジェクトのcall()メソッドを返すが、functionオブジェクト以外はこれを行うとundefinedを返すので結果としてfunctionオブジェクトかどうかを判定できる。

### Arrayオブジェクト

```javascript:before
a={foo:1};
b=[1,2,3];
// 16文字
console.log(Array.isArray(a)); // false
console.log(Array.isArray(b)); // true
// 18文字
console.log(a instanceof Array); // false
console.log(b instanceof Array); // true
```

```javascript:after
a={foo:1};
b=[1,2,3];
// 5文字
console.log(a.pop) // undefined
console.log(b.pop) // function pop()
```

pop()メソッドがあるかどうかでArrayオブジェクトであるかどうかを判定できる。

## for文の省略

### ブレースを省略する

```javascript:before
a=b=0;
for(var i=0;i<10;i++){
	a+=i;
	b+=i;
}
console.log(a,b);
```

```javascript:after
a=b=0;
for(var i=0;i<10;i++)a+=i,b+=i;
console.log(a,b);
```

```javascript:console.log
45 45
```

ブレースを省略できるのはステートメントが一つの場合だが、カンマ演算子を使えば単一ステートメントとして処理できる。

### デクリメントで記述し条件式を省略する

```javascript:before
a=b=0;
for(var i=0;i<10;i++){
	a+=i;
	b+=i;
}
console.log(a,b);
```

```javascript:after
a=b=0;
for(var i=10;i--;){
	a+=i;
	b+=i;
}
console.log(a,b);
```

```javascript:console.log
45 45
```

条件式と変化式が一緒になるので、iがfalse（つまり0）になるとループが終了する。

### for文のネストを省略する

```javascript:before
for(i=10;i--;)for(j=5;j--;)console.log(i,j);
```

```javascript:after
for(k=50;k--;)console.log(k/5|0,k%5);
```

iとjを掛けた数だけループさせ、元iの値はk/jを切り捨てた数、元jの値はk/jの剰余を使う。

## switch文の省略
jQueryを使って矢印キー「←、→」などに処理を行いたい場合、

```javascript:before
$(document).on('keypress', function(e){
	switch (e.keyCode){
		case 39:
			console.log('next');
			break;
		case 37:
			console.log('prev');
			break;
		default:
			break;
	}
});
```

```javascript:after
$(document).on('keypress', function(e){
	(b=({39:'next',37:'prev'})[e.keyCode])&&console.log(b);
});
```

```console.log
「←」を押すと'prev'、「→」を押すと'next'が出力され、それ以外のキーは無視する
```

連想配列を利用した出し分け。if文の省略（上記）や代入を処理文の中に書く方法（下記）を併用し、指定以外のキーを無視している。    
この方法は配列の例外処理などでも利用できる。

```javascript:before
['a','b','c','d'][x>3?3:x]
// xが3以上の場合は必ず'd'を出力する
```

```javascript:after
['a','b','c'][x]||'d'
// xが3以上の場合は必ず'd'を出力する
```

## 代入を処理文の中に書く

```javascript:before
mes='あ';
console.log(mes);
```

```javascript:after
console.log(mes='あ');
```

```javascript:console.log
'あ'
```

```javascript:before
a=1,b=2;
c=a+b;
console.log(c);
```

```javascript:after
c=(a=1)+(b=2);
console.log(c);
```

```javascript:console.log
3
```

## Template literalを使い文字列操作を省略する（ES6）

```javascript:before
a='い',b='う';
console.log('あ'+a+b+'え\nお');
```

```javascript:after
a='い',b='う';
console.log(`あ${a+b}え
お`);
```

```javascript:console.log
'あいうえお'
```

バックティック(\` \`) で囲むES6のTemplate literalは、文字列の中にプレースホルダー「${～}」で式や変数を挿入できるため、場合によってはショートコード化に役立つ。また改行もそのまま書けるため、エスケープ文字で書くより文字数を削減できる。

## 配列、オブジェクトの初期化

```javascript:before
var a = new Array(),
	b = new Object;
console.log(a,b);
```

```javascript:after
var a=[],b={};
console.log(a,b);
```

```javascript:console.log
[] Object {}
```

配列はブラケット（[]）、オブジェクトはブレース（{}）で初期化できる。

## functionをアロー関数で記述し省略する。(ES6)

```javascript:before
var a = function(r){
	return 'あ'+r;
};
console.log(a('い'));
```

```javascript:after
var a=(r)=>{return 'あ'+r};
console.log(a('い'));
```

```javascript:console.log
'あい'
```

ES6のアロー関数式は従来と比べ文字数を大幅に削減できる。

```javascript:after
var a=r=>'あ'+r;
console.log(a('い'));
```

引数が一つだけならパーレンを省略できる（引数を使わない場合は反対に省略できず、「a=()=>～」と書くことになるので使わなくても引数を入れたほうが文字数は減らせる）。またアロー関数を式として使う場合はreturnを省略でき、関数内の式が一つであればブレースも省略できる。