Web事業部実績紹介_Webサービス
Web事業部実績紹介_Webサービス
2016.04.28
#2
ES6のある星に生まれて

ES6の新しい変数宣言「let」と「const」の使い方

はやち

どうもですよ、はやちですよ₍₍ (ง ˘ω˘ )ว ⁾⁾

ECMAScript連載の第2回となります。前回は、ES6を最新ブラウザに対応させる「Babel」の使い方をご紹介しました。

今回以降では、ES6で新しく出た機能についてご紹介していきます。さて、本日は「let」と「const」の使い方を見ていきましょう( ˇωˇ)☝

ES5までの変数宣言は「var」のみ

ES5までは、変数を宣言するときvarしかありませんでした

しかし、ES6になってletとconstが導入され、挙動が変更されたので、これらを解説していきたいと思います( ˘ω˘)☞三☞シュッシュッ

letは「再宣言するとエラーが出る」

letは、varと同じように宣言を書いていきますが、再宣言をしたときにエラーが出る仕様になりました。

例を見てみましょう( ˘ω˘)☞三☞シュッシュッ

 

'use strict'

var test = 11;//大丈夫
var test = 13;//再宣言できる

console.log(test);//13が返ってくる

varの場合、同じ変数名で宣言したとき再宣言されて、13に変わります( ˇωˇ)☝

 

'use strict'

let test = 11;//大丈夫
test = 12;//再代入ができる

console.log(test);//12が返ってくる

let test = 15;//再宣言できない

letは、同じ変数名で宣言することはできませんが、値を代入できます( ˇωˇ)☝

constは「定数としてあつかえる宣言」

constは、“定数としてあつかえるようになる宣言”です。

いままでは、大文字で変数を定義し、定数として使用している変数であるとする暗黙のルールで運用されることがありました。しかし、ES6からは言語で定数を定義できるように。

例を見てみましょう( ˘ω˘)☞三☞シュッシュッ

 

'use strict'

var TEST = 11;//大丈夫
TEST = 12;//代入する事ができる。

console.log(TEST);//12が返ってくる

varの場合は、もちろん代入できますね( ˇωˇ)☝

 

'use strict'

const TEST = 11;//大丈夫
TEST = 12; //代入ができない エラーが返ってくる

constで動かしてみると、エラーが返ってきます( ˇωˇ)☝

 
constの注意点は、オブジェクトの書き換えができることです(◞‸◟) その例が下記となります。

const TEST = {
       a: 1,
       b: 0
   };

   TEST.a = 3;

   console.log(TEST);//Object {a: 3, b: 0}

もしconstをオブジェクト形式で設定する場合は、下記のように設定しましょう( ˘ω˘)☞三☞シュッシュッ

const TEST = Object.freeze({
       a: 1,
       b: 0
   });

   TEST.a = 3;

   console.log(TEST);//Cannot assign to read only property 'a' of object '#<Object>'

オブジェクトを凍結でき、書き換えられる心配がなくなります。

let・constではホイストが起きません

以前varでは、変数の巻き上げ現象「ホイスト」が起きていました。

‘use strict’;

console.log(test); 
// 値だけが入ってないと認識されてundefinedになる

var test = 10;

こちらのコードの裏側を見てみましょう。

‘use strict’;

var test; //変数宣言

console.log(test); 
// 値だけが入ってないと認識されてundefinedになる

test = 10; //変数の値

このように認識されます( ˇωˇ)☝

スコープは上から読まれていくはずなのに、変数の宣言だけこのような巻き上げ現象が起きるので、変数の宣言は必ず上に書くというルールで運用してました( ˇωˇ )

 

‘use strict’;

console.log(test); 
// 変数宣言がされていないと認識して
//ReferenceError: i is not definedとなる

let test = 10;

letやconstからは、varのような巻き上げ現象がなくなり、宣言されないと認識しない仕様になりました( ˇωˇ )

let・constでは、ブロック単位でスコープを生成します

スコープとは、変数の有効範囲のことで、プログラムのどの場所から参照できるかを決める概念のことです。

letとconstは、変数の特徴以外にスコープの挙動も変わりました。関数内のスコープだけでなく、ブロック単位でスコープを生成してくれます。

 

for (var i = 0; i < 10; i++) {
    console.log(i); // 1~9まででる
}

console.log(i); //10がでる

varの場合、forの中で1〜9までの数字が出てきますが、for外のconsoleにも反応をしてしまいます。

var = i;
for (i = 0; i < 10; i++) {
    console.log(i); // 1~9まででる
}

console.log(i); //10がでる

for内の変数は、実質このように巻き上げが生じてしまい、forの後でもアクセスが可能になってしまいます(◞‸◟)

 

for (let i = 0; i < 10; i++) {
    console.log(i); // 1~9まででる
}

console.log(i); //ReferenceError: i is not defined

letで変数を宣言すると、有効範囲がfor分内に限られるので、iは他からアクセスできなくなります( ˇωˇ)☝

このあとforやifでiを使用しても、またブロックスコープが生成されるので、実装に影響する心配はありませんね₍₍ (ง ˘ω˘ )ว ⁾⁾

ホイストとブロックスコープでの問題

このホイストとブロックスコープの影響で、1つの実装をご紹介します。

.buttonという要素があり、それを各クリックしたときに順番の数値を出すという実装にするとします( ˇωˇ )

 

var $btns = $(".button"); //10個あったとする

for (var i=0,len=$btns.length; i<len; ++i) {

  $btns.eq(i).on('click',function(){
     console.log(i);
   // どれ押しても10しか出てこない
  });
}

varだとiの変数が巻き上がってしまい、意図しない挙動になってしまいます(◞‸◟)コレジャナイ

 

let $btns = $(".button"); //10個あったとする

for (let i=0,len=$btns.length; i<len; ++i) {

  $btns.eq(i).on('click',function(){
     console.log(i);
     // それぞれ 0.1.2 と出てくる
  });
}

letで実装すると、やりたい挙動を実装することができました₍₍ (ง ˘ω˘ )ว ⁾⁾わーい

 
なんで意図する動きになったのでしょうか( ˇωˇ )? ここで、babelが変更したコードを見てみましょう( ˘ω˘)☞三☞シュッシュッ

var $btns = $(".button"); //10個あったとする

var _loop = function _loop(_i, _len) {

  $btns.eq(_i).on('click', function () {
    console.log(_i);
    // それぞれ 0.1.2 と出てくる
  });
};

for (var _i = 0, _len = $btns.length; _i < _len; ++_i) {
  _loop(_i, _len);
}

このように、クロージャーで実装されていることと同じ動きをletの方で実装しています。letはしゅごいですね( ˇωˇ )

まとめ

letとconstが新しく出てきたおかげで、変数の管理が少しわかりやすくなったと思います。

また、ブロックスコープのおかげで、かなり変数の影響範囲がブロック内でおさまり、同じ変数名を使用しても他の実装した機能への支障が減ると思われます( ˇωˇ ) 今後は、varを使わず、let,constを使うことをおすすめいたします( ˇωˇ )