読み飛ばしてください
おはようございます、しなもんです。
先日高校で情報のテストがあったのですが、無事にJavascriptの問題で詰みました。
(const使っとけばいいと思ってたら性質を利用する問題が出て詰んだ)
Pythonばっかり書いてる弊害がここに...
ので、この記事では改めてconst
, let
, var
の違いをまとめたいと思います。
そもそもなんで種類が分かれてるんだ?
そもそも、const
、let
、var
というものが別々に存在する理由はなんなのでしょうか?
Javascriptでは初期、var
しか存在しませんでした。
そのため、変数のスコープや再宣言ルールが曖昧で、
予期せぬバグが発生しやすいという問題がありました。
const
とlet
は、他の多くのプログラミング言語でも採用されている変数宣言方法であり、
Javascriptでもこれを取り入れることで、より信頼性の高い言語へ進化できたのです。
つまりは意図しないバグを防ぐために変数宣言時に制限を設けたのです。
コレ読めばとりあえず理解る?名前の由来
じゃあ名前の由来はなんなのでしょうか?
それぞれの名前は、以下の意味を英語で表しています。
- const (constant): 不変、定数
- let (let): 許す、させる
- var (variable): 変数
const
は、値を変更できない不変変数を宣言するために使用されるため、
不変を意味するそのままの名が付けられました。
let
は、ブロックスコープ変数を宣言し、その変数に値を代入することを可能にするため、
変数に値を代入することを許す、値を与えるからlet
と命名されたと考えられます。
var
は、変数を宣言するために使用される汎用的なキーワードであり、
歴史的な経緯からこの名が付けられています。一番ありふれたものです。
改めてそれぞれを知ってみよう
const
- 再宣言も再代入も不可です。
- すでに宣言済みの変数名で再度宣言しようとすると、エラーが発生します。
- 宣言時に必ず値を初期化する必要があります。
言い換えると、
- 同じ名前で変数を作りなおすことができない(再宣言不可)
- 一度値を入れたら入れなおすことができない(再代入不可)
- 変数を作るときには必ず値を入れなければいけない
例えば、
const PI = 3.14159;
と定義した後に
PI = 3.14159; // エラー: 'PI' is already declared
もう一度代入しようとすると普通にエラーを吐きます。
let
- 再代入は可能ですが、再宣言は不可です。
- 同じスコープ内で同じ変数名を再度宣言しようとすると、エラーが発生します。
- 宣言時に初期化しても初期化しなくても構いません。
これも言い換えると、
- 同じ名前で変数を作りなおすことができない(再宣言不可)
- 値を何度でも入れなおすことができる(再代入)
- 変数を作るときに必ず値を入れる必要がない
つまり、
let count;
とりあえず変数だけ用意する ←可能
count = 10;
後から値を代入する ←可能(上書きもできる)
let count = 20; // エラー: 'count' is already declared
ただし同じ変数を作ることはできないです。
var
- 再宣言と再代入は両方とも可能です。
- 同じスコープ内で同じ変数名を再度宣言しても、新しい宣言が古い宣言を置き換えます。
- 宣言時に初期化しても初期化しなくても構いません。
要するに
- 同じ名前で変数を作ってもいい(再宣言)
- 値を何回でも入なおしていい(再代入)
- 変数を作るときに必ず値を入れる必要がない
var message; // 変数を作るときに必ず値を入れる必要がない
message = 'World'; // 値を上書きできる
var message = 'JavaScript'; // 同じ名前で変数を作ってもいい
それぞれの影響範囲は違う
const
とlet
はブロックスコープを持ちます。
ブロックとは、{}
で囲まれたコードのことです。
if 文、for 文、while 文などのループ、関数の中などがブロックにあたります。
変数は宣言されたブロック内でのみ有効です。
ブロックの外からはその変数にアクセスできません。
var
は関数スコープを持ちます。
関数の中で宣言された変数は、その関数内でのみ有効です。
関数外からはその変数にアクセスできません。
そのため、同じ名前の変数を別の関数で宣言しても、互いに干渉しません。
// const
if (true) {
const num = 100;
console.log(num); // 100が出力される
}
console.log(num); // エラー: 'num' is not defined
// let
if (true) {
let num = 200;
console.log(num); // 200が出力される
}
console.log(num); // エラー: 'num' is not defined
// var
function func1() {
var message = 'Hello';
console.log(message); // 'Hello'が出力される
}
function func2() {
var message = 'World';
console.log(message); // 'World'が出力される
}
func1();
func2();
ブロック内でも関数内でもない外側で定義されたら?
先述した情報のテストで、私はここで詰みました。
上に書いたことは分かっていても、一番外側で定義されたらどうなるか覚えていませんでした...
コードの一番外側に変数が宣言された場合、その変数はグローバルスコープを持ちます。
プログラムのどこからでもその変数にアクセスできます。
関数の中やブロックの中であっても、その変数を参照することができます。
同じ名前の変数が別のスコープで宣言されていても、グローバル変数が優先的に参照されます。
// グローバル変数宣言
var message = 'Hello, World!';
function func1() {
console.log(message); // 'Hello, World!'が出力される
}
function func2() {
var message = 'JavaScript'; // 別の変数
console.log(message); // 'JavaScript'が出力される
}
func1();
func2();
console.log(message); // 'Hello, World!'が出力される
覚えておきましょう。
巻き上げってなんぞや?
const
とlet
は巻き上げが発生しません。
変数の宣言が、実際にその変数を使用する場所よりも後に書かれていても、問題なく動作します。
var
は巻き上げが発生します。
変数の宣言が、実際にその変数を使用する場所よりも後に書かれている場合、その変数は undefined
値になります。
// const
console.log(num); // エラー: 'num' is not defined
const num = 100;
// let
console.log(num); // エラー: 'num' is not defined
let num = 200;
// var
var num = 100;
console.log(num); // 100が出力される
まとめ
これはずっと言われているのですが、基本的にconst
を使用するように心がけましょう。
変数の値が変わらないことが確実な場合は、const
で宣言することで、
コードの意図が明確になり、後々の修正も楽になります。
また、関数やブロックの外で変数を定義する際も、変数がグローバル変数になってしまうため、
影響が大きくならないよう気を付けるべきだと言われています。
では。