JavaScriptを書いているとこの変数の宣言constで良いんだっけ?letじゃないとまずいのかな?と迷うことがある。それぞれのキーワードの違いをメモしておく。
それぞれの特徴のまとめ
var
- ブロックスコープがない
- 同名の再宣言がスコープ関係なくできる
- 宣言に初期化が必要ない
let
- ブロックスコープがある
- 同名の再宣言が同じスコープ内ではできない
- 再代入できる
- 宣言に初期化が必要ない
const
- ブロックスコープがある
- 同名の再宣言が同じスコープ内ではできない
- 再代入できない
- 宣言に初期化が必要
varの例
varで宣言された変数はいわゆる関数スコープの範囲で参照され、ブロックスコープは適用されない。例えば、if文の中で宣言された変数もその外から参照可能。また、初期化も不要でundefinedになるだけでエラーにはならない。再定義しても怒られない。
function hoge() {
var x;
console.log(x);
//undefined
var x = 1;
console.log(x);
// 1
if(true) {
var x = 2;
console.log(x);
// 2
}
console.log(x);
// 2
}
hoge();
letの例
function hoge() {
let x = 1;
console.log(x);
// 1
if(true) {
let x = 2;
console.log(x);
// 2
}
console.log(x);
// 1
}
hoge();
上の例のようにブロックスコープが働いているのがわかる。
var x = 1;
let x = 2;
console.log(x);
// Uncaught SyntaxError: Identifier 'x' has already been declared
let x;
x = 2;
console.log(x);
// 2
上のように再宣言はできないが、初期化は不要で再代入も可能。
constの例
constもブロックスコープはletと変わらない。
function hoge() {
const x = 1;
console.log(x);
// 1
if(true) {
const x = 2;
console.log(x);
// 2
}
console.log(x);
// 1
}
hoge();
初期化してないと下のように怒られるし、再代入もできない。この辺はletと違う。
const x;
x = 2;
console.log(x);
// Uncaught SyntaxError: Missing initializer in const declaration
const x = 2;
x = 3;
console.log(x);
// Uncaught TypeError: Assignment to constant variable.
ただし、再代入できないだけなので以下のようにオブジェクトのプロパティや配列の中身を変えることはできる。
const obj = {hoge:"aaa"};
obj.hoge = "bbb";
console.log(obj);
// { hoge: 'bbb' }
const arr = [1,2,3];
arr[1] = 10;
console.log(arr);
// [ 1, 10, 3 ]
巻き上げの挙動の違い
var,let,constでは巻き上げの挙動が違うので気をつける。
console.log(hoge);
var hoge = "aaa"
//undefined
varで宣言した場合はundefinedになる。それに対してletでは参照エラーになる。letでも巻き上げ自体は起こっている。
console.log(hoge);
let hoge = "aaa"
//ReferenceError: hoge is not defined
constの場合もエラーになります。SyntaxErrorになっている。letと微妙に違うのは再代入不可な分なのかな。
console.log(hoge);
const hoge = "aaa"
//SyntaxError: Identifier 'hoge' has already been declared
まとめ
constって定数って聞くから値の変更不可能って思いこむところあるけど、あくまで再代入できないだけだからプロパティとかは変更できるのは忘れがちなのかと思った。そもそも値が変わるような処理は意味合いが変わっているだろうから、別の名前つけて再定義することを考える。