変数と宣言
プログラミング言語には、文字列や数値などのデータに名前をつけることで、繰り返し利用できるようにする変数という機能があります。
JavaScriptには「これは変数です」という宣言をするキーワードとして、
const
、let
、var
の3つがあります。
var
はもっとも古くからある変数宣言のキーワードですが、意図しない動作を作りやすい問題が知られています。
そのためECMAScript 2015で、var
の問題を改善するためにconst
とlet
という新しいキーワードが導入されました。
この章ではconst
、let
、var
の順に、それぞれの方法で宣言した変数の違いについて見ていきます。
[ES2015] const
const
キーワードでは、再代入できない変数の宣言とその変数が参照する値(初期値)を定義できます。
次のように、const
キーワードに続いて変数名
を書き、代入演算子(=
)の右辺に変数の初期値
を書いて変数を定義できます。
const 変数名 = 初期値;
次のコードではbookTitle
という変数を宣言し、初期値が"JavaScript Primer"
という文字列であることを定義しています。
const bookTitle = "JavaScript Primer";
const
、let
、var
どのキーワードも共通の仕組みですが、変数同士を,
(カンマ)で区切ることにより、同時に複数の変数を定義できます。
次のコードでは、bookTitle
とbookCategory
という変数を順番に定義しています。
const bookTitle = "JavaScript Primer",
bookCategory = "プログラミング";
これは次のように書いた場合と同じ意味になります。
const bookTitle = "JavaScript Primer";
const bookCategory = "プログラミング";
また、const
は再代入できない変数を宣言するキーワードです。
そのため、const
キーワードで宣言した変数に対して、後から値を代入することはできません。
次のコードでは、const
で宣言した変数bookTitle
に対して値を再代入しているため、次のようなエラー(TypeError
)が発生します。
エラーが発生するとそれ以降の処理は実行されなくなります。
const bookTitle = "JavaScript Primer";
bookTitle = "新しいタイトル"; // => TypeError: invalid assignment to const 'bookTitle'
一般的に変数への再代入は「変数の値は最初に定義した値と常に同じである」という参照透過性と呼ばれるルールを壊すため、バグを発生させやすい要因として知られています。そのため、変数に対して値を再代入する必要がない場合は、const
キーワードで変数宣言することを推奨しています。
変数に値を再代入したいケースとして、ループなどの反復処理の途中で特定の変数が参照する値を変化させたい場合があります。
そのような場合には、変数への再代入が可能なlet
キーワードを利用します。
[ES2015] let
let
キーワードでは、値の再代入が可能な変数を宣言できます。
let
の使い方はconst
とほとんど同じです。
次のコードでは、bookTitle
という変数を宣言し、初期値が"JavaScript Primer"
という文字列であることを定義しています。
let bookTitle = "JavaScript Primer";
let
はconst
とは異なり、初期値を指定しない変数も定義できます。
初期値が指定されなかった変数はデフォルト値としてundefined
という値で初期化されます(undefined
は値が未定義ということを表す値です)。
次のコードでは、bookTitle
という変数を宣言しています。
このときbookTitle
には初期値が指定されていないため、デフォルト値としてundefined
で初期化されます。
let bookTitle;
// `bookTitle`は自動的に`undefined`という値になる
このlet
で宣言されたbookTitle
という変数には、代入演算子(=
)を使うことで値を代入できます。
代入演算子(=
)の右側には変数へ代入する値を書きますが、ここでは"JavaScript Primer"
という文字列を代入しています。
let bookTitle;
bookTitle = "JavaScript Primer";
let
で宣言した変数に対しては何度でも値の代入が可能です。
let count = 0;
count = 1;
count = 2;
count = 3;
var
var
キーワードでは、値の再代入が可能な変数を宣言できます。
var
の使い方はlet
とほとんど同じです。
var bookTitle = "JavaScript Primer";
var
では、let
と同じように初期値がない変数を宣言でき、変数に対して値の再代入もできます。
var bookTitle;
bookTitle = "JavaScript Primer";
bookTitle = "新しいタイトル";
var
の問題
var
はlet
とよく似ていますが、var
キーワードには同じ名前の変数を再定義できてしまう問題があります。
let
やconst
では、同じ名前の変数を再定義しようとすると、次のような構文エラー(SyntaxError
)が発生します。
そのため、間違えて変数を二重に定義してしまうというミスを防ぐことができます。
// "x"という変数名で変数を定義する
let x;
// 同じ名前の変数"x"を定義するとSyntaxErrorとなる
let x; // => SyntaxError: redeclaration of let x
一方、var
は同じ名前の変数を再定義できます。
これは意図せずに同じ変数名で定義してもエラーとならずに、値を上書きしてしまいます。
// "x"という変数を定義する
var x = 1;
// 同じ名前の変数"x"を定義できる
var x = 2;
// 変数xは2となる
またvar
には変数の巻き上げと呼ばれる意図しない挙動があり、let
やconst
ではこの問題が解消されています。
var
による変数の巻き上げの問題については「関数とスコープ」の章で解説します。
そのため、現時点では「let
はvar
を改善したバージョン」ということだけ覚えておくとよいです。
このように、var
にはさまざまな問題があります。
また、ほとんどすべてのケースでvar
はconst
かlet
に置き換えが可能です。
そのため、これから書くコードに対してvar
を利用することは避けたほうがよいでしょう。
[コラム] なぜlet
やconst
は追加されたのか?
ECMAScript 2015では、var
そのものを改善するのではなく、新しくconst
とlet
というキーワードを追加することで、var
の問題を回避できるようにしました。var
自体の動作を変更しなかったのは、後方互換性のためです。
なぜなら、var
の挙動自体を変更してしまうと、すでにvar
で書かれたコードの動作が変わってしまい、動かなくなるアプリケーションが出てくるためです。
新しくconst
やlet
などのキーワードをECMAScript仕様に追加しても、そのキーワードを使っているソースコードは追加時点では存在しません。1
そのため、const
やlet
が追加されても後方互換性には影響がありません。
このように、ECMAScriptでは機能を追加する際にも後方互換性を重視しているため、var
自体の挙動は変更されませんでした。
変数名に使える名前のルール
ここまででconst
、let
、var
での変数宣言とそれぞれの特徴について見てきました。
どのキーワードにおいても宣言できる変数に利用できる名前のルールは同じです。
また、このルールは変数の名前や関数の名前といったJavaScriptの識別子において共通するルールとなります。
変数名の名前(識別子)には、次のルールがあります。
- 半角のアルファベット、
_
(アンダースコア)、$
(ダラー)、数字を組み合わせた名前にする - 変数名は数字から開始できない
- 予約語と被る名前は利用できない
変数の名前は、半角のアルファベットであるA
からZ
(大文字)とa
からz
(小文字)、_
(アンダースコア)、$
(ダラー)、数字の0
から9
を組み合わせた名前にします。
JavaScriptでは、アルファベットの大文字と小文字は区別されます。
これらに加えて、ひらがなや一部の漢字なども変数名に利用できますが、全角の文字列が混在すると環境によって扱いにくいこともあるためお勧めしません。
let $; // OK: $が利用できる
let _title; // OK: _が利用できる
let jquery; // OK: 小文字のアルファベットが利用できる
let TITLE; // OK: 大文字のアルファベットが利用できる
let es2015; // OK: 数字は先頭以外なら利用できる
let 日本語の変数名; // OK: 一部の漢字や日本語も利用できる
変数名に数字を含めることはできますが、変数名を数字から開始することはできません。 これは変数名と数値が区別できなくなってしまうためです。
let 1st; // NG: 数字から始まっている
let 123; // NG: 数字のみで構成されている
また、予約語として定義されているキーワードは変数名には利用できません。
予約語とは、let
のように構文として意味を持つキーワードのことです。
予約語の一覧は予約語 - JavaScript | MDNで確認できますが、基本的には構文として利用される名前が予約されています。
let let; // NG: `let`は変数宣言のために予約されているので利用できない
let if; // NG: `if`はif文のために予約されているので利用できない
[コラム] const
は定数ではない
const
は「再代入できない変数」を定義する変数宣言であり、必ずしも定数を定義するわけではありません。
定数とは、一度定義した名前(変数名)が常に同じ値を示すものです。
JavaScriptでも、const
宣言によって定数に近い変数を定義できます。
次のように、const
宣言によって定義した変数を、変更できないプリミティブな値で初期化すれば、それは実質的に定数です。
プリミティブな値とは、数値や文字列などオブジェクト以外のデータです(詳細は「データ型とリテラル」の章で解説します)。
// TEN_NUMBERという変数は常に10という値を示す
const TEN_NUMBER = 10;
しかし、JavaScriptではオブジェクトなどもconst
宣言できます。
次のコードのように、オブジェクトという値そのものは、初期化したあとでも変更できます。
// `const`でオブジェクトを定義している
const object = {
key: "値"
};
// オブジェクトそのものは変更できてしまう
object.key = "新しい値";
このように、const
で宣言した変数が常に同じ値を示すとは限らないため、定数とは呼べません
(詳細は「オブジェクト」の章で解説します)。
またconst
には、変数名の命名規則はなく、代入できる値にも制限はありません。
そのため、const
宣言の特性として「再代入できない変数」を定義すると理解しておくのがよいでしょう。
まとめ
この章では、JavaScriptにおける変数を宣言するキーワードとしてconst
、let
、var
があることについて学びました。
const
は、再代入できない変数を宣言できるlet
は、再代入ができる変数を宣言できるvar
は、再代入ができる変数を宣言できるが、いくつかの問題が知られている- 変数の名前(識別子)には利用できる名前のルールがある
var
はほとんどすべてのケースでlet
やconst
に置き換えが可能です。
const
は再代入できない変数を定義するキーワードです。再代入を禁止することで、ミスから発生するバグを減らすことが期待できます。
このため変数を宣言する場合には、まずconst
で定義できないかを検討し、できない場合はlet
を使うことを推奨しています。
1.let
やconst
はECMAScript 2015以前に予約語として定義されていたため、既存のコードと衝突する可能性はありませんでした。 ↩