21
21

More than 5 years have passed since last update.

JavaScriptのスコープとクロージャとletステートメント

Last updated at Posted at 2014-05-26

スコープ

javascriptのスコープは少々特殊である。
javascriptはブロックによるスコープを作らず、関数によってのみスコープを作る。

ブロックによるスコープを作らない例
for(var i = 0;i < 10;i++){
    var sum = sum || 0;
    sum += i;
}
console.log(sum);    //45, エラーにならない
関数によってスコープが作られる例
for(var i = 0;i < 10;i++){
    function add(){
        var sum = sum || 0;
        sum += i;
    }
    add();
}
console.log(sum);    //エラー, ReferenceError: sum is not defined

クロージャ

クロージャは外のスコープの値への参照保持する。

var name = 'test';
var age = 20;
function myAlert(){
    alert(name+', hello!' + ' age:'+age);
}
myAlert();    //test, hello! age:20 とアラートされる

注意することは"参照"を保持しているということである。
myAlertは実行すると常に同じ文章を表示するわけではない。
例えば以下のようにmyAlertを定義した後、name,ageを変更すると表示内容が変わる。

var name = 'test';
var age = 20;
function myAlert(){
    alert(name+', hello!' + ' age:'+age);
}
myAlert();    //test, hello! age:20 とアラートされる
name = 'test2';
age = 30;
myAlert();    //test2, hello! age:30 とアラートされる

この仕様は以下のような罠を含んでいる。
いつかあなたが絶対に引っかかる、ある一つのJavaScriptの罠 - Qiita

letステートメント

JavaScript 1.7ではletステートメントを使用することでブロックスコープを実現できる。

for(var i = 0;i < 10;i++){
    let sum = sum || 0;    //ループの最初ではsumはundefinedのため常に0で初期化される
    sum += i;
}
console.log(sum);    //エラー, ReferenceError: sum is not defined

このletステートメントを使用すると上記の記事にあるJavaScriptの罠を容易に解決できる。

//firefoxのコンソールなどで実行可能
for (var i = 0; i < 3; i++) {
    let _i = i;
    setTimeout(function() {
        console.log(_i);
    }, 0);
}

//0, 1, 2 とログがでる

まとめ

ブロックによるスコープをつくらないために変数名をよく考えてつける必要がある。
非同期処理でクロージャを使う場合は注意する。
JavaScript 1.7はletステートメント以外にも便利な機能があるので早く使えるようになって欲しい。

21
21
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
21