変数のスコープ
このレッスンで分かること
letとconstで宣言した変数は、それを囲む{ }の中だけで生きます- 作業用の変数を関数の外に置くと、2 回目の呼び出しに前回が残ります
2 回呼ぶと、前回の結果が混ざる
作業用の変数を、うっかり関数の外に置いてしまった例です。1 回目は正しく動くので、まず気付けません。
JavaScript
let line = "";
function joinTags(tags) {
for (const tag of tags) {
line += "#" + tag + " ";
}
return line;
}
console.log(joinTags(["HTML", "CSS"]));
// => #HTML #CSS
console.log(joinTags(["JavaScript"]));
// => #HTML #CSS #JavaScript2 回目に、前回のタグが残りました。line は関数の外にあるので、関数が終わっても値が消えないからです。しかもこの line を他の場所でも使っていたら、まったく関係のない画面の表示まで狂います。原因は joinTags の中にあるのに、症状は遠くに出る。これがいちばん追いにくいバグです。
変数が見えるのは、宣言した { } の中だけ
宣言した変数がどこから使えるか、という範囲をスコープと呼びます。let と const で宣言した変数は、それを囲んでいる { } の中だけで生きます。if でも for でも、{ } があればそこが境界です。
JavaScript
if (true) {
const message = "公開中";
console.log(message); // 公開中
}
console.log(message); // ReferenceError
for (let i = 0; i < 3; i++) {
console.log(i); // 0 1 2
}
console.log(i); // ReferenceError逆に、外側で宣言した変数は内側から見えます。内側から外側は見える、外側から内側は見えない。部屋の中からは廊下が見えるけれど、廊下から部屋の中は見えない、という関係です。
直し方は、宣言を関数の中に入れるだけ
さきほどの例は、let を 1 つ動かすだけで直ります。
JavaScript
function joinTags(tags) {
let line = "";
for (const tag of tags) {
line += "#" + tag + " ";
}
return line;
}line は呼ばれるたびに新しく作られ、関数が終われば消えます。外には何の影響も与えません。関数の中で使う作業用の変数は、必ず関数の中で宣言する。これを守るだけで、原因不明のバグの多くが消えます。
変数はできるだけ狭い範囲で宣言してください。範囲が狭ければ、その変数を気にしなければならない場所も狭くなり、読むのも直すのも楽になります。
内側で外側と同じ名前を宣言すると、内側では外側が隠れます。これをシャドーイングと呼びます。外側を書き換えてしまうよりは安全ですが、同じ名前の変数が 2 つあることに読み手は気付きにくいので、内側では別の名前を付けるほうが親切です。
よくある間違い
- ブロックの外で使おうとする —
ifの中でconst result = ...と宣言し、ifの外でreturn result;と書くとエラーになります。使う範囲でいちばん外側のブロックで宣言してください - 宣言そのものを書き忘れる —
letもconstも付けずにいきなりtotal = 0と書くと、ローカル変数のつもりが外側への代入になります。エラーは出ないので、症状だけが遠くに現れます
要件
- 関数名は sumViews、引数は数値の配列 views 1 つにすること
- 合計を入れる変数は関数の中で let を使って宣言すること
- 関数の外の変数を書き換えないこと
- 空配列を渡されたら 0 を返すこと
入出力例
sumViews([120,80,45]) → 245
sumViews([120,80,45]) → 245
sumViews([10]) → 10
sumViews([]) → 0
sumViews([0,0,0]) → 0