【JavaScriptクイズ】第1問:変数を宣言するには
JavaScriptの文法や便利な使い方について、気軽なクイズ形式で解説する記事を書いていきます。
今回のテーマは「変数の宣言」です。では、さっそく問題です!
問題
配列に格納された数値の合計を表示する、次のようなJavaScriptのプログラムがあります。
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // この数値の合計を……
sum = 0; // この変数に格納する
// 合計を計算
for (x of numbers) {
sum += x;
}
// 結果を表示
console.log("sum = " + sum);
このプログラムは、例えばNode.jsを使って次のように実行できます。
node quiz.js
sum = 55
1から10までの合計は55なので、正しい計算結果になっていることが分かります。
さて、JavaScriptには「厳格モード(strict mode)」と呼ばれるモードがありまして、これを使えば実行が速くなるかもしれないなどのメリットがあります。そこで次のように、プログラムの1行目に"use strict"
を追加してみました。これで、プログラムは「厳格モード」で実行されるようになります。
"use strict";
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // この数値の合計を……
sum = 0; // この変数に格納する
// 合計を計算
for (x of numbers) {
sum += x;
}
// 結果を表示
console.log("sum = " + sum);
すると、プログラムがエラーで動かなくなってしまいました。実行しようとすると、次のようなエラーメッセージが表示されるのです。
ReferenceError: numbers is not defined
どのように直せば正常に動作するプログラムになるか、分かりますか?
ヒントを見る?
「厳格モード」は、新しい変数が意図せず作られないように配慮されています。まだ「宣言」されていない変数に代入しようとしたら、エラーとして扱われます。
答えを見る?
次のようにlet
を付けて変数を宣言すれば、エラーは発生しなくなります。
"use strict";
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // この数値の合計を……
let sum = 0; // この変数に格納する
// 合計を計算
for (let x of numbers) {
sum += x;
}
// 結果を表示
console.log("sum = " + sum);
または次のように、値が変わらない変数にはconst
を付けるのでもOKです。
"use strict";
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // この数値の合計を……
let sum = 0; // この変数に格納する
// 合計を計算
for (const x of numbers) {
sum += x;
}
// 結果を表示
console.log("sum = " + sum);
解説
問題のエラーメッセージは……
ReferenceError: numbers is not defined
日本語に訳すと次のような意味です。
参照エラー: numbersは定義されていません
ここで、numbers
はプログラム中に出てくる変数名です。このプログラムでは、以下の3つの変数が使われています。
numbers
sum
x
「厳格モード」では、変数が最初に登場するところでlet
かconst
を付けて「宣言」しなければなりません。問題のプログラムでは、どの変数も宣言されていなかったためエラーになっていました。プログラムはnumbers
のエラーが出た時点で停止してしまいましたが、実際にはsum
とx
にもエラーがあるということです。
let
は、通常の変数を表します。次のように、値を変更してOKです。
"use strict";
let x = 1;
x = 2; // letの変数は、値を変更してOK
const
は定数を表します。初期化したあとで値を変更しようとすると、エラーになります。
"use strict";
const x = 1;
x = 2; // エラー:constは定数なので、値を変更できない
では、3つの変数にlet
かconst
を付けていきましょう。
numbersはどっち?
numbers
は、今回の「答え」ではlet
としました。
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
でも、この変数は初期化したあとに値が変わらないので、定数だと考えることもできます。つまり、次のようにconst
を付けても正解です。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const
を付けた場合は、次のように配列全体を定義し直そうとするとエラーになります。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
numbers = [11, 12, 13, 14, 15]; // エラー:constなので変更できない
ところが、少し意外かもしれませんが、次のように配列の内容に変更を加えるのはOKです。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
numbers[0] = -1; // constでも、これはOK
numbers.push(99); // これもOK
さてさて、上記をふまえて、let
とconst
をどのように使い分ければいいのかというのは議論が絶えないところかなと思います。
原則としては、「const
にできるのなら、そうすべき」と考えればいいでしょう。この方針にしたがう場合、プログラム中に表れる変数は、かなりのものがconst
になるのではないかと思います。
これに対して、今回の「答え」では「とくに定数っぽいものだけconst
にする」という方針でlet
を採用しました。「円周率は3.14だ」とか、「曜日の種類は7つだ」というような、明らかな定数にconst
を付ける考え方です。
どちらの方針が正しいかは決められませんが、プログラムをどちらの方針で書くかは決めておくのがいいかと思います。
sumはどっち?
sum
は、ループの内側で値が書き換えられています。
// 合計を計算
for (let x of numbers) {
sum += x; // ここで値が変わる
}
したがって、let
を付けて宣言しなければなりません。const
だと、エラーが発生します。
let sum = 0;
xはどっち?
x
は、今回の「答え」ではlet
としました。これは、for-of
ループが回るたびにx
の値が変わるように見えるからなのですが……
// 合計を計算
for (let x of numbers) {
……
}
実は、次のようにconst
にしてもエラーは発生しません。
// 合計を計算
for (const x of numbers) {
……
}
これがなぜOKなのかというと、変数x
はループが1回まわるごとに新しく作られるので、厳密には値が変わっているわけではないからです。
でも、イメージ的にはx
の値が更新されていくように感じますよね?そのため、この場合はlet
を使うほうが分かりやすいという人もいるのではないかと思います。
まとめ
JavaScriptは、"use strict"
と書くと「厳格モード(strict mode)」で実行できます。「厳格モード」では、変数を「宣言」する必要があるなど、文法がより厳格になります。また、実行速度が速くなる可能性も、見逃せないメリットです。
既存のプログラムを「厳格モード」に置き換えようと思うと、なかなか苦労するかもしれません。でも、これから書き始めるプログラムなら、それほど大変ではないと思います。とにかく1行目に"use strict"
と書いてしまってから、プログラミングにとりかかるのがおすすめです。
変数を「宣言」するとき、let
とconst
をどのように使い分けるかは考えどころです。「const
にできるのなら、そうすべき」と考えるのが原則ですが、絶対にそうしなければならないというわけではありません。とくにチーム開発では、どういうルールにするか話し合って決めるのがいいでしょう。
なお、let
とconst
については下記の本でも取り上げています。
また、下記のページではC言語のconst
について取り上げています。よろしければ参考にしてみてください!
Discussion