これだけは覚えておこうES2015(旧ES6)【let, const】

このエントリーをはてなブックマークに追加

これからの標準となっていくES2015(ES6)!ただ、増える文法や機能がありすぎてげんなりしちゃう!という人もたくさんいると思いますので、私が これだけは覚えておいた方がいい! と思う文法や機能を独断と偏見でまとめてちょっとずつ解説していきたいと思うシリーズです。

let, const

第一弾として登場するのが letconst です。これが何かというと、ES5までは変数を宣言するときに var しか存在しませんでした。この var、意外と仕様を知らない人が多いため、思わぬ罠にはまることがあります。

結論

var で宣言した変数はホイスト(巻き上げられる)されるし、 function 単位でのスコープしか存在しない。( iffor などの ブロック内 で宣言してもブロック内のスコープというものは 存在しない

それに対して、 letconst はホイストされず、宣言された場所で初期化されるし、 iffor のブロック内で宣言したものは ブロック内でしか存在しない ブロックスコープ が適用される。

解説

ホイストされない

ホイストは変数の宣言が巻き上げられることです。文字で言われてもぱっとしないと思うので、コードで書くと↓

'use strict';

console.log(a);

var a = 10;

ここで console で何が出力されるかわかる人はホイストがわかっている人です。 答えは

undefined

var はホイストされるので↓と書いてあるのと同じ意味なんです。

'use strict';
var a;

console.log(a);

a = 10;

なので undefined になります。

letconst はホイストされないので、同じような↓のコードでも結果が変わります。

'use strict';

console.log(a);

let a = 10; // constでも同じ

// 結果
// ReferenceError: a is not defined

ホイストされないが故に console.log のときには a が存在しないので ReferenceError になります。

letとconstの違い

↑の違いはわかったとして、 letconst の違いはどうなるのでしょう???これは他の言語などやったことある人ならわかると思いますが、 const定数 です。なので、一度値を定めたらその値を変更することができません。仮に変更しようとすると↓のように怒られます。

'use strict';

const a = 10;

a = 11;

// 結果
// a = 11;
//   ^
// TypeError: Assignment to constant variable.

ブロックスコープ

letconst の登場によって、ブロックスコープが使えるようになりました。他言語から来た人が勘違いしやすかったところです。まず、ES5までは

'use strict';

var a = 10;

if(true) {
    var a = 20;
}

console.log(a);

と書いた場合に console に出力されるのはなんと

20

です。 ブロックスコープ に慣れている人からすると違和感ありあり( 10 じゃないの?)ですが、 var には ブロックスコープ が無いので、 if の中の a も、外の a も同じスコープに存在しています。よって、 if の外の a を上書いてしまうのです。

特に間違えやすいのが↓の結果です。

'use strict'

for(var i = 0; i < 2; i++) {
    setTimeout(function() { console.log(i) }, 2000);
}

普通に考えたら 01が出力されそうですよね?でも違うんです。結果は

22 と、 2 が2回表示されます。

何故かと言うと、 for のブロックスコープが存在しないからです。ホイストもされるので↑のコードは↓と書いているのと一緒です。

'use strict'

var i;
for(i = 0; i < 2; i++) {
    setTimeout(function() { console.log(i) }, 2000);
}

なので、2秒後に出力するころには i の値は 2 になっているんです。 これが let const になると ブロックスコープ が適用されるので、直感的な動きをしてくれるようになります。

'use strict';

let a = 10;

if(true) {
    let a = 20;
}

console.log(a);
// 結果:10

for にも ブロックスコープ が適用されます。

'use strict'

for(let i = 0; i < 2; i++) {
    setTimeout(function() { console.log(i) }, 2000);
}

// 結果
// 0
// 1

まとめ

letconst いろいろとだらだら書きましたが、ようするに直感的に変数宣言できるようになった!って覚えてもらったら十分な気がします(笑)人によっては letconst なんか必要ない! var だけで十分だ!って言う人もいますが、私は個人的に letconst が好きです。将来的にはブラウザの最適化の恩恵とかも受けれそうですしね。次回はアロー関数(=>)について解説します!

おまけ

ちなみに Babel などのトランスパイラを使った場合に↑のES2015 for 文はES5では↓になります。

'use strict';

// 関数をクッションにすることで独自のスコープを
// 生成できるので、iの値が保持される仕組み
var _loop = function _loop(i) {
    setTimeout(function () {
          console.log(i);
            }, 2000);
};

for (var i = 0; i < 2; i++) {
    _loop(i);
}
Written on April 15, 2016
このエントリーをはてなブックマークに追加