JavaScript

変数と定数

 変数とは、プログラムで使われる値を、名前付きで管理するラベルのようなものです。プログラムを書いていると、文字列や数値などの同じ値を何度も使ったり、一時的に値を保存したりしたいケースが出てきます。このようなときに、次の例のように変数で値に対して名前を付けておけば、好きなタイミングで繰り返し使用できます。

>> Sample Page


// 変数を使用しない場合
console.log("こんにちは");    // "こんにちは"という値は、この場限りの使用になる。


// 変数を使用した場合
let hello = "こんにちは!";   // helloという変数名で "こんにちは!"という値を取得できるようにする。すると、変数名を指定することで繰り返し使用できる。
let bye = "さようなら";
console.log(hello);
console.log(hello);         // 何回でも繰り返し使える。
console.log(bye);

 変数を使用する際に let というキーワードを記述します。また、一度、値を設定すると、それ以降、変更ができない特殊な変数もあり、そのような変数を定数と呼びます。

変数の宣言

 変数は、その変数を使用する前に変数の宣言を行う必要があります。変数の宣言方法はプログラミング言語の種類によって異なりますが、JavaScriptの場合は let、const、var という3つのキーワードで変数を宣言します。変数は宣言することによって初めて、変数名で値を管理できる状態になります。

変数の宣言方法


let 変数名 = 値;

 変数名(識別子とも言います)はある程度決まった形式で命名しますが、基本的に半角英数字で命名すると考えてください。

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

 それでは、変数を宣言して簡単なコードを実行してみましょう。次の例では、"こんにちは" という値に対して hello という名前を付けています。そして、その変数を window.alert という機能(関数)に渡すことで、"こんにちは" とダイアログに表示します。なお、このように値に対して変数を設定することを「値を変数に代入する」と言います。

ダイアログに "こんにちは" を表示


let hello = "こんにちは";    // 値を変数に代入する。
window.alert(hello);       // 変数を関数に渡す。

 このプログラムでは、変数に値を代入するときに等号(=)を使っています。プログラムにおける等号(=)は代入を表し、数式のような左辺と右辺の値が等しいことを表すわけではないことに注意してください。プログラムの場合には、= は右辺の値を左辺に代入するということをしっかり覚えておきましょう。

3つのキーワードの違い

var とは
var では再宣言、再代入が可能です。

var example = '初期値OK';
example = '再代入OK';
var example = '再宣言OK';

let とは
let では再宣言が禁止されています。

let example = '初期値OK';
example = '再代入OK';
let example = '再宣言NG';

const とは
const では再宣言、再代入が禁止されています。

const example = '初期値OK';
example = '再代入NG';
const example = '再宣言NG';

var

 varキーワードでは、値の再代入が可能な変数を宣言できます。


var bookTitle;

 これは、bookTitle という名前の変数を宣言しています。この場合、bookTitle は値が代入されていないため、デフォルト値として underfined(未定義値) で初期化されています。ようするに「入れ物(変数)」は作ったけど、「中身(値)は空っぽ」って感じです。

 この bookTitle という変数には、= 演算子を使うことで値を代入することができます。


var bookTitle;
bookTitle = "JavaScriptの本";

 これで、bookTitle という変数に、「JavaScriptの本」という文字列を代入しました。

 ここまでの、「変数の宣言 → 値の代入」までの流れを省略して、変数の宣言と同時に初期値を代入することができます。


var bookTitle = "JavaScriptの本";

 これも、上の処理と同様に、bookTitle という変数に、「JavaScriptの本」という文字列を代入しています。

 また、変数の宣言は、カンマ( , )で区切ることによって、複数の変数を定義することができます。


var bookTitle;
var bookCategory;

と、別々に宣言しても問題ありませんが、


var bookTitle, bookCategory;

と省略することができます。

 もちろん、カンマ( , )で区切って省略した状態でも、初期値の代入をすることができます。


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

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


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

 ここの例では、bookTitle という変数に、「JavaScriptの本」という文字列を代入し、bookCategory に「プログラミング」という文字列を代入しています。


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

 カンマ( , )の後ろで改行をしておくと、後ほどの修正や、書き直したい場合などのメンテナンス時には見やすいかもしれません。けど、これだとわざわざカンマ( , )で区切った意味がなさそうにも見えます。処理状況に応じて、使い分ける必要がありそうです。

let

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


let bookTitle = "JavaScriptの本";
bookTitle = "新しいJavaScriptの本";

 let で宣言した変数 bookTitle に「JavaScriptの本」を代入した後にもう一度、今度は「新しいJavaScriptの本」と違う文字列を代入しました。この"再代入"処理は問題ありません。


let bookTitle = "JavaScriptの本";
let bookTitle = "新しいJavaScriptの本";

 let で宣言した変数 bookTitle に「JavaScriptの本」を代入した後に、今度は let で再宣言して「新しいJavaScriptの本」を代入しようとしましたが、こちらの"再宣言"は、エラーとなります。

エラーメッセージで、 SyntaxError: Cannot declare a let variable twice: 'bookTitle'. (構文エラー:let 変数を2回宣言出来ません:'bookTitle'。) と、表示されました。 ようするに「bookTitle を2回宣言しちゃダメですよー」と教えてくれました。

 エラーが発生するということはプログラムの処理がここで止まって正常に動作しなくなりますのでご注意ください。

const

 値を変更できない変数を定数と呼びます。定数は、宣言した後に値の代入を行えません。この性質から、定数は、あとで変更されて困る値を扱うときに使用されます。定数を宣言するには、constというキーワードを使用します。

 constキーワードも基本的な使い方は varや letと同じですが、値の再代入が出来ません。また、これも letと同じように再宣言も出来ません。

Syntax


const 変数名 = 値;


const bookTitle = "JavaScriptの本";

 varや letのキーワードでは再代入が可能なので、宣言だけを行った後に必要な値を別途代入しても問題ありませんでしたが、constキーワードは再代入ができないので、宣言と同時に値(初期値)を代入(定義)する必要があります。

 宣言だけを行った場合はエラーになり、 SyntaxError: const declared variable 'bookTitle' must have an initializer. (構文エラー:const で宣言した変数 'bookTitle' には初期値が必要です) と、メッセージが表示されました。

 letキーワードのところでも書きましたが、エラーが発生するということはプログラムの処理がここで止まって正常に動作しなくなりますのでご注意ください。

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

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

varの問題

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

 let や const では、同じ名前の変数を再定義しようとすると、構文エラー(SyntaxError)が発生します。 そのため、間違えて変数を二重に定義してしまうというミスを防ぐことができます。

 一方、var は同じ名前の変数を再定義できます。これは意図せずに同じ変数名で定義してもエラーとならずに、値を上書きしてしまいます。


// "x" という変数を定義する
var x = 1;
// 同じ変数名の変数 "x" を定義できる
var x = 2;
// 変数 x は 2 となる

 また var には変数の巻き上げと呼ばれる意図しない挙動があり、let や const ではこの問題が解消されています。そのため、現時点では「let は var を改善したバージョン」ということだけ覚えておくと良さそうです。

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

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

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

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

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

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

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


const $ = "$";
// OK: $が利用できる

const _title = "_title";
// OK: _が利用できる

const jquery = "jquery";
// OK: 小文字のアルファベットが利用できる

const TITLE = "TITLE";
// OK: 大文字のアルファベットが利用できる

const es2015 = "es2015";
// OK: 数字は先頭以外なら利用できる

const 日本語の変数名 = "日本語の変数名";
// OK: 一部の漢字や日本語も利用できる

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


var 1st;
// NG: 数字から始まっている

var 123;
// NG: 数字のみで構成されている

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


var var;
// NG: 'var' は変数宣言のために予約されているので利用できない

var if;
// NG: 'if' は if 文のために予約されているので利用できない

変数の本質

 プログラム上で使われる値はすべてメモリ上に保管されており、メモリ上の場所はアドレスと呼ばれる数値で表現されます(メモリは、メモリ空間、メモリスペースとも言います)。一般的にアドレスを表すときには16進数が使われますが、ここでは簡略化のために番地を使ってメモリ空間を表現します。例えば、プログラム中で "こんにちは"、"さようなら" という値が使われた場合には、下図のようなイメージになります。

 この図から、仮に "こんにちは" や "さようなら" という値を取得したい場合には、それぞれ3番地と4番地に保管されている値を取得すれば良いことがわかります。そして、このアドレス(番地)を保持しているのが変数です。

 そのため、変数名を指定すると、その変数が保持しているアドレスの値を取得できます。これが変数と値の関係です。変数は、値そのものではなく、あくまで値の保管先の場所(アドレス)を保持しているということを覚えておいてください。このように、値が格納されているメモリのアドレスを保持していることを、「変数は値への参照を保持している」と言います。

 つまり、次のような変数に格納された値を取得するコードをメモリ空間で表すと、下図のようなイメージになります。


let hello = "こんにちは";
console.log(hello);

 図のように、変数hello が保持しているのは、"こんにちは" という値が格納されているメモリのアドレス(3番地)の情報です。そのため、変数hello の値をプログラム中で取得すると、図の①〜④のような流れで、変数hello の参照先の値が取得されます。

 プログラミングを学習していると、参照という言葉が頻繁に出てきます。プログラムにおける参照とは、メモリ空間上のアドレスのことを指します。変数は「値への参照を格納する入れ物」です。そのため、「値」そのものと、変数に格納される「値への参照(アドレス)」は、異なるものであることに注意してください。プログラムの実行中に変数を取得するときには、JavaScriptエンジンは変数が保持している参照先の値を取得します。

値の再代入

 letを使って宣言した変数の値を上書きする方法について確認します。なお、変数の値を変更することを値の再代入と言います。

 ここでは、次のようなプログラムが実行された場合を考えてみます。


let greeting = "こんにちは";
console.log(greeting);

greeting = "さようなら";      // 値の再代入
console.log(greeting);

 このように値を再代入した時のメモリ空間上のイメージは、下図のようになります。

 変数に別の値が代入されると、変数が保持しているアドレスが(代入された値のアドレスに)切り替わります。使われなくなった "こんにちは" という値は、他に使用箇所がない場合には自動的にメモリから削除されます。

 値の再代入と似た用語に変数の再宣言があります。変数の再宣言とは、同じ変数名で重複して変数宣言を行うことを言います。letや constでは、変数の再宣言を行うとエラーになるので、注意してください。また、値の再代入と混同しないように注意しましょう。

letや constでは変数の再宣言は行えない


let fruit = 'りんご';
let fruit = 'りんご';     // 同じ変数名で変数を宣言しているためエラーが発生!

変数のコピー

 値の再代入では、変数が持つアドレスが切り替わることを学びました。では、変数を他の変数に代入したときはどうなるか、次の例で見てみます。


let hello = "こんにちは";
let greeting = hello;

 この場合、値が格納されているアドレスがそのまま受け渡されます。

 この場合には、helloと greetingが保持するアドレス(3番地)は同じなので、"こんにちは" という値を他のメモリ領域にコピーするのは効率的ではありません。そのため、このような場合には、値を格納しているアドレスを受け渡すことによって、メモリを効率的に使用できます。

 では、このあとさらに greetingに "さようなら" を代入して、greetingの値が変更された場合にはどうなるでしょう。

変数のコピー後、さらに値を代入


let hello = "こんにちは";
let greeting = hello;
greeting = "さようなら";

 この場合も、前項の「値の再代入」と同じく、複数の保持している参照先が変わります。そのため、greetingの値が変更された場合には、greetingは新しい参照先の4番地へ参照を保持することになります。

 ここで説明した「変数はアドレスを保持している」という考え方は、プログラムを深く理解する上で重要なので、頭の片隅に入れておきましょう。