JavaScriptを学ぶ基本の1つに、変数の使い方があります。変数は、number(数値)、string(文字列)、array(配列)など、あらゆる型(データ型を参照)を含む入れ物です。変数は、あとでアプリケーション内で使用する(たとえば、値の参照)ために名前が付けられます。
本記事では、変数の使い方と、宣言による違いを紹介します。
変数の宣言と初期化、代入の違い
変数の宣言の違いに入る前に、変数のライフサイクルを見ていきます。
- 宣言(Declaration):変数は付けられた名前で適切なスコープ(関数の中など)に登録される段階
- 初期化(Initialization):変数は宣言されたとき、自動的に初期化され、JavaScriptのエンジンによってメモリが確保される段階
- 代入(Assignment):変数に特定の値が代入される段階
宣言の型
varは、JavaScriptがリリースされたときからずっと使われてきました。ES6(ES2015)から、新たにletとconstが使えるようになりました。ブラウザーの互換性はこちらで確認してください。
var
構文:
var x; // Declaration and initialization
x = "Hello World"; // Assignment
// Or all in one
var y = "Hello World";
ECMAScript 6まで代替案がなかったため、おそらくこの宣言が一番使われています。varで宣言された変数のスコープは、宣言された関数内になります。特定の関数内で宣言されない変数はグローバルになります。
例:
function sayHello(){
var hello = "Hello World";
return hello;
}
console.log(hello);
例を実行するとReferenceError: hello is not definedというエラーが表示されます。helloという変数が、sayHelloという関数内だけで有効だからです。しかし、次のようにすれば動作します。変数がconsole.log(hello)と同じスコープでグローバルに定義されているからです。
var hello = "Hello World";
function sayHello(){
return hello;
}
console.log(hello);
let
構文:
let x; // Declaration and initialization
x = "Hello World"; // Assignment
// Or all in one
let y = "Hello World";
letはモダンなJavaScriptにおいて、varの後継です。letのスコープは、関数内だけでなく、ブロック文内に制限されます。ブロック文は常に{と}で囲われます(たとえば、if文やループ文など)。letの良いところは、変数のスコープが小さくなるため、エラーになる可能性を減らせることです。
例:
var name = "Peter";
if(name === "Peter"){
let hello = "Hello Peter";
} else {
let hello = "Hi";
}
console.log(hello);
例を実行するとReferenceError: hello is not definedというエラーが表示されます。helloという関数がブロック内(例だとif文内)でのみ有効だからです。しかし、次のようにすれば動作します。
var name = "Peter";
if(name === "Peter"){
let hello = "Hello Peter";
console.log(hello);
} else {
let hello = "Hi";
console.log(hello);
}
const
構文:
const x = "Hello World";
正確に言うと、定数は変数ではありません。定数の特徴は、宣言時に値を代入すると、再度代入できないことです。constはletと同様に、スコープはブロック内です。
定数は、アプリケーションが動いているあいだはずっと、値の変更をしてはいけません。そのため、上書きしようとするとエラーが発生します。
もう1つのグローバル変数の作り方
いままで紹介した宣言は、関数の外で宣言するとグローバルになりますが、もし変数の前にvar、let、constを書き忘れると、関数内で宣言しても自動的にグローバルになります。
例:
function sayHello(){
hello = "Hello World";
return hello;
}
sayHello();
console.log(hello);
例を実行すると、コンソールにHello Worldと表示されます。代入式hello =の前に変数の宣言がなく、変数がグローバルになっているからです。
メモ:誤ってグローバル変数にすることを防ぐには厳格モードが役に立ちます。
巻き上げによる一時的デッドゾーン
var、let、constとほかの違いは、変数の巻き上げに関することです。変数の宣言は、いつもそのスコープの先頭に巻き上げられます。以下に例を紹介します。
console.log(hello);
var hello;
hello = "I'm a variable";
この例は、以下と同様の意味になります。
var hello;
console.log(hello);
hello = "I'm a variable";
上の2例を実行すると、コンソールにundefinedと表示されます。もし、先頭にvar hello;がなければReferenceErrorが表示されます。
この巻き上げによる挙動は、varだけではなくletとconstでも起こります。先に述べたように、宣言されていないvar変数にアクセスしようとすると、JavaScriptが初期化時に代入するundefinedが値として返されます。
しかし、letとconst変数は宣言前にアクセスするとエラーが発生します。この2つの変数は宣言の前にアクセスできないということです。変数のスコープ内で、変数が宣言される前までの区間を一時的デッドゾーン(変数にアクセスできない期間)と呼びます。
巻き上げについては、JavaScriptの変数スコープと巻き上げの解説を参考にしてください。
最後に
エラーになる確率を下げるためには、できるだけletかconstを使うべきです。もし本当にvarを使う必要があるなら、スコープ内の1番上で宣言をして、巻き上げによる予期しないエラーを防ぎましょう。
※本記事はMark Brown、Mev-Raelが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者のみなさんに感謝します。
(原文:Quick Tip: How to Declare Variables in JavaScript)
[翻訳:萩原伸悟/編集:Livit]