JavaScript の変数
JavaScript では変数を宣言するのに、2種類の方法があります。
- let による変数の宣言 - ブロックスコープ
- var による変数の宣言 - 関数スコープ
let による変数の宣言
JavaScript ES6 以降では、変数の宣言に let キーワードが使えます。
例えば変数 x と y を宣言し、 それぞれ 1 と 3 を代入して、その結果を変数 z に代入して、z の値をコンソールに出力するなら、 次のようにできます。
let x = 1;
let y = 3;
let z = x + y;
console.log(z); // 4 が出力される
変数が有効な範囲をスコープ (scope) といいます。
let を使って宣言した変数のスコープは、ブロックスコープ です。 ブロックスコープというのは、平たく言えばいちばん内側の { と } に囲まれた範囲のことです。
var による変数の宣言
変数を宣言するキーワードは let の他に、var キーワードも使えます。
var キーワードは初期の JavaScript から存在しています。かなり古いブラウザ環境もサポートしなければいけない場合は let が使えないので、 var しか使うことができません。
let と var は何が違うのでしょうか?
var キーワードを用いて宣言した変数は関数スコープ (function scope) になります。 つまり、ある関数内で宣言した変数は、その関数内で有効です。
function f1() {
var x = 123;
console.log(x); // 123
}
f1();
しかも var では、変数を宣言した場所より前方 (上側) でも有効です。let の場合は、宣言した後でしか使うことはできません。
概念的に変数宣言が関数内の上部で行われるのと同じ効果があります。これを変数のホイスティングなどと言います。
例えば、次の関数 f1() 内の {} で囲まれたブロック内で変数 x が宣言します。それをブロック外、しかも、宣言より前方 (上側) で読み取ります。
function f1() {
console.log(x);
x = 123;
console.log(x);
{
var x = 'abc'; // ここで宣言
}
console.log(x);
}
f1();
このコードは、(あまり望ましい書き方ではありませんが) 有効なコードです。エラーなく実行され、次のような結果になります。
変数の初期化
let でも var でも、 変数の宣言と初期化は同時にできます。
let x = 1;
var y = 10;
初期化しなくても構いませんが、何も割り当てられていない時は undefined という値になります。
let x;
var y;
変数の宣言を省略?
strict モードで実行される箇所では、 let または var を用いて変数を宣言する必要があります。
例えば、次のコードを実行すると、「変数が定義されていない」という旨のエラーが発生します。
'use strict';
x = 1;
strict モードではない場合、みかけ上は必ずしも変数を宣言する必要はありません。
例えば、次のコードは let も varも使っていませんが、問題なく実行されます。
x = 1;
console.log(x); // 1
function f1() {
x = 123;
console.log(x); // 123
}
f1();
console.log(x); // 123
console.log(window.hasOwnProperty('x')); // true
これは x が、 Global オブジェクトのプロパティとして作られたからです。
Global オブジェクトがよくわからない、という方は、「Global オブジェクト」を読んでから、この先をお読みいただくとわかりやすいと思います。
このため、変数の宣言が省略できたということではありませんが、見かけ上、x は変数のように使えています。
尚、上記のコードは次のようにはじめに var を付けたの場合と全く同一になります。
var x = 1;
console.log(x); // 1
...以下同じ
これは var を用いて関数外で変数を宣言しているので、変数がグローバルスコープになるために、Global オブジェクトのプロパティとして x が作成されるからです。
もし関数 f1() 内で var を使って変数を宣言した場合は、どうなるでしょうか。
このときは関数内の変数 x のスコープは f1() 内だけなので、関数外で使われている x (=window.x) とは別物になります。
x = 1;
console.log(x); // window.x = 1
function f1() {
var x = 123;
console.log(x); // x = 123
}
f1();
console.log(x); // window.x = 1
console.log(window.hasOwnProperty('x')); // true
実行結果は次の通り、関数内で x に新しい値を割り当てていますが、関数外の x には影響していません。