変数と宣言

プログラミング言語には、文字列や数値などのデータに名前を付けることで、繰り返し利用できるようにする変数という機能があります。

JavaScriptでは「これは変数です」という宣言をするキーワードとして、 constletvarの3つがあります。

varはもっとも古くからある変数宣言のキーワードですが、意図しない動作を作りやすい問題が知られています。 そのためECMAScript 2015で、varの問題を改善するためにconstletという新しいキーワードが導入されました。

この章ではconstletvarの順に、それぞれの方法で宣言した変数の違いについて見ていきます。

[ES2015] const

constキーワードでは、再代入できない変数の宣言とその変数が参照する値(初期値)を定義できます。

次のように、constキーワードに続いて変数名を書き、代入演算子(=)の右辺に変数の初期値を書いて変数を定義できます。

const 変数名 = 初期値;

次のコードではbookTitleという変数を宣言し、初期値が"JavaScriptの本"という文字列であることを定義しています。

const bookTitle = "JavaScriptの本";

constletvarどのキーワードも共通の仕組みですが、変数同士を,(カンマ)で区切ることにより、同時に複数の変数を定義できます。

次のコードでは、bookTitlebookCategoryという変数を順番に定義しています。

const bookTitle = "JavaScriptの本",
      bookCategory = "プログラミング";

これは次のように書いた場合と同じ意味になります。

const bookTitle = "JavaScriptの本";
const bookCategory = "プログラミング";

また、constは再代入できない変数を宣言するキーワードです。 そのため、constキーワードで宣言した変数に対して、後から値を再代入することはできません。

次のコードでは、constで宣言した変数bookTitleに対して値を再代入しているため、次のようなエラー(TypeError)が発生します。 エラーが発生するとそれ以降の処理は実行されなくなります。

const bookTitle = "JavaScriptの本";
bookTitle = "新しいタイトル"; // => TypeError: invalid assignment to const 'bookTitle'

一般的に変数への再代入は「変数の値は最初に定義した値と常に同じである」という参照透過性と呼ばれるルールを壊すため、バグを発生させやすい要因として知られています。そのため、変数に対して値を再代入する必要がない場合は、constキーワードで変数宣言することを推奨しています。

変数に値を再代入をしたいケースとして、ループなどの反復処理の途中で特定の変数が参照する値を変化させたい場合があります。 そのような場合には、変数への再代入が可能なletキーワードを利用します。

[ES2015] let

letキーワードでは、値の再代入が可能な変数を宣言できます。 letの使い方はconstとほとんど同じです。

次のコードでは、bookTitleという変数を宣言し、初期値を"JavaScriptの本"という文字列であることを定義しています。

let bookTitle = "JavaScriptの本";

letconstとは異なり、初期値を指定しない変数も定義できます。 初期値が指定されなかった変数はデフォルト値としてundefinedという値で初期化されます。(undefinedは値が未定義ということを表す値です)

次のコードでは、bookTitleという変数を宣言しています。 このときbookTitleには初期値が指定されていないため、デフォルト値としてundefinedで初期化されます。

let bookTitle;
// `bookTitle`は自動的に`undefined`という値になる

このletで宣言されたbookTitleという変数には、代入演算子(=)を使うことで値を代入できます。 代入演算子(=)の右側には変数へ代入する値を書きますが、ここでは"JavaScriptの本"という文字列を代入しています。

let bookTitle;
bookTitle = "JavaScriptの本";

letで宣言した変数に対しては何度でも値の代入が可能です。

let count = 0;
count = 1;
count = 2;
count = 3;

var

varキーワードでは、値の再代入が可能な変数を宣言できます。 varの使い方はletとほとんど同じです。

var bookTitle = "JavaScriptの本";

varでは、letと同じように初期値がない変数を宣言でき、変数に対して値の再代入もできます。

var bookTitle;
bookTitle = "JavaScriptの本";
bookTitle = "新しいタイトル";

varの問題

varletとよく似ていますが、varキーワードは同じ名前の変数を再定義できてしまう問題があります。

letconstでは、同じ名前の変数を再定義しようとすると、次のような構文エラー(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には変数の巻き上げと呼ばれる意図しない挙動があります。 変数の巻き上げはスコープという変数などを参照できる範囲を決める性質と深く関係しています。 スコープについては「関数とスコープ」の章で扱うため、現時点では「letvarを改善したバージョン」ということだけ覚えておくとよいです。

このように、varにはさまざまな問題があります。 また、ほとんどすべてのケースでvarconstletに置き換えが可能です。 そのため、これから書くコードに対してvarを利用することは避けた方がよいでしょう。

[コラム] なぜletconstは追加されたのか?

ECMAScript 2015では、varそのものを改善するのではなく、新しくconstletというキーワードが追加することで、varの問題を回避できるようにしました。var自体の動作を変更しなかったのは、後方互換性のためです。

なぜなら、varの挙動自体を変更してしまうと、すでにvarで書かれたコードの動作が変わってしまい、動かなくなるアプリケーションが出てくるためです。 新しくconstletなどのキーワードをECMAScript仕様に追加しても、そのキーワードを使っているソースコードは追加時点では存在しません。1 そのため、constletが追加されても後方互換性には影響がありません。

このように、ECMAScriptでは機能を追加する際にも後方互換性を重視しているため、var自体の挙動は変更されませんでした。

変数名に使える名前のルール

ここまででconstletvarでの変数宣言とそれぞれの特徴について見てきました。 どのキーワードにおいても宣言できる変数に利用できる名前のルールは同じです。 また、このルールは変数の名前や関数の名前といったJavaScriptの識別子において共通するルールとなります。

変数名の名前(識別子)には、次のルールがあります。

  1. 半角のアルファベット、_(アンダースコア)、$(ダラー)、数字を組み合わせた名前にする
  2. 変数名は数字から開始できない
  3. 予約語と被る名前は利用できない

変数の名前は、半角のアルファベットであるAからZ(大文字)とaからz(小文字)、_(アンダースコア)、$(ダラー)、数字の0から9を組み合わせた名前にします。JavaScriptでは、アルファベットの大文字と小文字は区別します。

これらに加えて、ひらがなや一部の漢字なども変数名に利用できますが、全角の文字列が混在すると環境によって扱いにくいこともあるためお勧めしません。

var $; // OK: $が利用できる
var _title; // OK: _が利用できる
var jquery; // OK: 小文字のアルファベットが利用できる
var TITLE; // OK: 大文字のアルファベットが利用できる
var es2015; // OK: 数字は先頭以外なら利用できる
var 日本語の変数名; // OK: 一部の漢字や日本語も利用できる

変数名に数字を含めることはできますが、変数名を数字から開始はできません。 これは変数名と数値が区別できなくなってしまうためです。

var 1st; // NG: 数字から始まっている
var 123; // NG: 数字のみで構成されている

また、予約語として定義されているキーワードは変数名には利用できません。 予約語とは、varのように構文として意味をもつキーワードのことです。 予約語の一覧は予約語 - JavaScript | MDNで確認できますが、基本的には構文として利用される名前が予約されています。

var var; // NG: `var`は変数宣言のために予約されているので利用できない
var 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における変数宣言を行うキーワードとしてconstletvarがあることについて学びました。

  • constは、再代入できない変数を宣言できる
  • letは、再代入ができる変数を宣言できる
  • varは、再代入ができる変数を宣言できるが、いくつかの問題が知られている
  • 変数の名前(識別子)には利用できる名前のルールがある

varはほとんどすべてのケースでletconstに置き換えが可能です。 constは再代入できない変数を定義するキーワードです。再代入を禁止することで、ミスから発生するバグを減らすことが期待できます。 そのため変数を宣言する場合には、まずconstで定義できないかを検討し、できない場合はletを使うことを推奨しています。

1. letconstはECMAScript 2015以前に予約語として定義されたため、既存のコードと衝突する可能性がありませんでした。