こちらの記事は以下の書籍を参考に執筆しました
-
入門JavaScriptプログラミング
プロパティ名と変数名が同じになる場合はこのように簡潔にできる。
##letによる変数の巻き上げ
巻き上げとは、変数が宣言されたスコープの内側では、変数がスコープ全体(letならブロック全体,varなら関数全体)を消費する振る舞いのこと。
...そう言われてもよくわからない。
まずは例を見てみる。
if (condition) {
//----- myDataのスコープはここから -----
doSomePrework();
/*その他のコード*/
let myData = getData();
/*その他のコード*/
doSomePostwork();
//----- ここまで -----
}
上記の例ではmyData
変数はif文のブロックスコープ内にあり、
まだ宣言されていなくてもアクセスできる。
//----- myDataのスコープはここから -----
と //----- ここまで -----
の間のどこにmyData
を宣言してもどこからでもアクセスできるということ。
次の例は少々難しい。
//----- 外側のmyDataのスコープはここから -----
let myData = getDefaultData();
if (condition) {
//----- myDataのスコープはここから -----
doSomePrework(myData);
/*その他のコード*/
let myData = getData();
/*その他のコード*/
doSomePostwork();
}
//----- ドト側のmyDataのスコープはここまで -----
上記の場合myData
は2つ存在する。
ややこしいのはdoSomePrework
関数が呼び出された時点で引数のmyData
は外側のmyData
であるというのは間違であるということだ。
つまり、
内部のmyData
はスコープ全体(ifブロック全体)を消費しているため、doSomePrework
関数に入るのはこの内側のmyData
だ。
このように宣言される前でも変数を巻き上げて使用できてしまうのが変数巻き上げである。
#letで巻き上げられる変数へ宣言前にアクセスすると?
letは変数をブロックの先頭へ巻き上げ、varは関数の先頭へ巻き上げる。
letで宣言された変数が宣言される前にスコープ内でアクセスされた場合、参照エラー(ReferenceError)となる。
varではスコープ内であれば宣言される前であってもアクセスできるが、値は常に未定義となる。
console.log(foo) //参照エラー
let foo=2;
以下のコードの結果はどうなるだろうか
let num = 0;
function getNum() {
if (!num) {
let num = 1;
}
return num;
}
console.log(getNum()); //結果は??
答えは1ではない。
解説すると、
let num = 0;
function getNum() {
if (!num) {
//----- 内部のnumスコープはここから -----
let num = 1;
//----- 内部のnumスコープはここまで -----
}
return num; //新しい let 変数はスコープを外れたため、この変数は0のまま
}
console.log(getNum());
つまり、はif
文内で宣言されたnum
そのスコープ内でしか有効でないためgetNum
関数のreturn
されるnum
は外側のものであるということだ。
これを解決するにはnumに1を代入する時にletを取ればいい。
let num = 0;
function getNum() {
if (!num) {
//letをとる。
num = 1;
}
return num;
}
console.log(getNum()); //1