はじめに
JavaScriptでは「let」と「var」があり、どちらも変数を宣言できるのですが、その性質には違いがあります。本記事ではその違いについてまとめます。
var
var のスコープ
スコープとは、宣言された変数が有効な範囲のことです。var宣言は、関数の外で宣言される場合はグローバルスコープ(どこでも使える)となり、関数の中で宣言される場合はローカルスコープ(関数の中だけで使える)となります。
var greet = "how are you?";
function newFunction() {
var hello = "hello";
}
console.log(greet); // how are you?
console.log(hello); // ReferenceError: hello is not defined
上の例では、変数greetは関数の外で宣言しているため、グローバルスコープです。一方、変数helloは関数の中で宣言しているため、関数の外ではアクセスできません。
var japanese = false;
var greet = "how are you?";
if(japanese) {
var hello = "こんにちは";
}else{
var hello = "hello";
}
console.log(greet); // how are you?
console.log(hello); // hello
こちらの例では変数helloはelseの{ }内で宣言されていますが、関数内ではないので、{ }の外でも変数にアクセスできます。
var は再宣言が可能
varでは同名の変数を再宣言することが可能です。
var hello = "hello";
var hello = "こんにちは";
console.log(hello); // こんにちは
varは上の例のように再宣言してもエラーを起こさず、実質上書きされます。
var hello = "hello";
hello = "こんにちは";
console.log(hello); // こんにちは
こちらのように、再宣言せず更新することも可能です。
var 宣言の巻き上げ
varによる宣言では、「巻き上げ」と呼ばれる処理が行われます。
console.log(hello); // undefined
var hello ="hello";
上の例ではvar宣言がconsole.logの後に書かれています。しかし、処理の順番としては、helloの変数作成と初期値「undefined」の代入が最初に行われ、console.log()の後に、"hello"の代入が行われます。console.log()の時点で変数helloには初期値「undefined」が入力されていることがわかります。
var 宣言の問題点
var japanese = false;
var greet = "how are you?";
if(japanese) {
var greet = "こんにちは";
}else{
var greet = "hello";
}
console.log(greet); // hello
上の例ではelse内での処理により、最初に宣言した変数greetが上書きされています。意図して行っていれば問題ありませんが、気づかずに宣言した場合は様々なバグの原因となるため、注意が必要です。
let
let のスコープ
let宣言はブロックスコープと呼ばれ、{ }に挟まれた範囲でのみ有効となります。
let japanese = false;
let greet = "how are you?";
if(japanese) {
let hello = "こんにちは";
}else{
let hello = "hello";
}
console.log(greet); // how are you?
console.log(hello); // ReferenceError: hello is not defined
var 宣言の場合と違い、{ }内で宣言された変数helloに{ }外ではアクセスできません。
let は再宣言が不可能
letでは同名の変数を再宣言することができません。
let hello = "hello";
let hello = "こんにちは"; //Uncaught SyntaxError: Identifier 'hello' has already been declared
console.log(hello);
上記のコードはエラーを返します。
let hello = "hello";
hello = "こんにちは";
console.log(hello); // こんにちは
一方で、こちらのように、再宣言せず更新することは可能になっています。
let 宣言の巻き上げ
let 宣言にも、「巻き上げ」処理が行われます。しかし、var とは挙動が異なります。
console.log(hello); // ReferenceError: Cannot access 'hello' before initialization
let hello ="hello";
let 宣言の巻き上げ処理では、helloの変数作成のみ最初に行われ、初期値の代入はありません。よって空白のデータを参照し、エラーを返しています。
まとめ
・var 宣言はグローバルスコープまたは関数スコープであるのに対し、let 宣言はブロックスコープ。
・varで宣言された変数は再宣言可能だが、letで宣言された変数は再宣言不可能。
・varもletも巻き上げ処理が行われるが、letでは初期値の代入がないので注意。
・varは{ }外で宣言された変数を{ }内で上書きしてしまうので、扱いには注意が必要。(と言うよりも、基本的に変数にはletを使った方がよさそう)
var | let | |
---|---|---|
再宣言 | 可能 | 不可能 |
スコープ(有効範囲) | グローバルスコープ / 関数スコープ | ブロックスコープ({ }の中で有効) |