2.1 変数と定数

(1/1)
変数
AI生成コンテンツ / AI-generated contents
ここから、JavaScriptでプログラムを書くためのルール(文法)を説明していく。
JavaScriptの文法は、Ecma Internationalが ECMAScript (エクマスクリプト) として標準化している。
ここでは、クラスが利用できるようになったバージョン ES2015(ES6) (2015年6月)に則って説明する。
まず、変数と定数の宣言や名前、有効範囲(スコープ)について事例を交えながら説明しよう。
(2026年8月16日)事実確認、全体整合性の確認、校正、サンプル・プログラムの修正

目次

サンプル・プログラム

変数と名前

電卓のメモリ・キー
変数は名前を付けたデータの保管場所
プログラムでデータ(数値、文字列など)を一時的に保管する場所として変数がある。電卓のメモリ・キー(M+)が複数あり、各々に自由に名前を付けられる仕組みと考えていただきたい。
変数の名前は識別子と呼ばれ、利用できる文字に制限がある。
JavaScriptの識別子には、英字、アンダースコア (_)、ドル記号 ($) のほか、多くのUnicode文字を使える。2文字目以降には数字 (0–9) も使えるが、数字から始めることはできない。英字の大文字と小文字は区別される。日本語も利用できるが、入力や共同作業のしやすさを考え、このシリーズでは半角英数字を中心に使う。
識別子に使える文字や予約語は言語によって異なるので、別の言語でも同じとは限らない。
変数名は、誰でも分かるような読みやすいものにすべきだが、これについては「コラム:命名規則」をご覧いただきたい。

また、次の文字列はJavaScriptの予約語であり、変数名や関数名として使えない。背景色がライトブルーの文字列は、厳格モードで予約される語である。awaitやyieldなど、実行環境によって扱いが変わる語もあるため、いずれも識別子には使わない方がよい。
await break case catch class
const continue debugger default delete
do else enum export extends
false finally for function if
import implements in instanceof interface
let new null package private
protected public return static super
switch this throw true try
typeof var void while with
yield    
予約語はプログラミング言語によって異なるが、少なくとも上表の文字列を使うのは避けた方がいい。

var1.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     let hoge = 1;
  23:     document.getElementById('let1').innerHTML = hoge;
  24:     let Hoge = 2;
  25:     document.getElementById('let2').innerHTML = Hoge;
  26:     let _hoge1 = 3;
  27:     document.getElementById('let3').innerHTML = _hoge1;
  28:     _hoge1 = 4;
  29:     document.getElementById('let4').innerHTML = _hoge1;
  30:     //let 3hoge = 4;
  31:     //document.getElementById('let2').innerHTML = 3hoge;
  32: }
  33: </script>

"var1.html" は、変数 hoge, Hoge, _hoge1 に数値を代入、表示させるプログラムだ。各々の変数名が異なるものとして区別されていることが分かる。
コメントアウトした変数 3hoge を実行しようとするとエラーになる。
たとえばGoogle Chromeでは、[F12]キーをクリックすると、下図のようにJavaScriptのエラーを表示するようになる。他のブラウザにも同様機能が備わっており、JavaScriptの簡易デバッガとして役立つだろう。

変数 _hoge1 を二度、使い回していることに注目してほしい。一度使った変数に別の値を代入することを再代入という。
再代入のときには let を使わない。let は変数を最初に使うときの宣言ととらえていただきたい。
ブラウザ:エラー表示
ブラウザの開発者ツールに表示されたエラー

練習問題:変数と名前

グローバル変数とローカル変数

変数には有効範囲(スコープ)がある。
var で宣言した変数は、関数の内側なら関数スコープ、関数の外側ならグローバルスコープを持つ。varはブロックスコープを持たない。
letconst で宣言した変数は、宣言したブロック内で通用するブロックスコープを持つ。
ブラウザでは window がグローバルオブジェクトになる。windowは変数名として使えるものの、組み込みのwindowを隠して混乱を招くため避けるべきである。windowsは別の識別子であり、予約語ではない。

let宣言は、2015年(平成27年)にリリースされた JavaScript ES2015(ES6) で実装された。それまでは var宣言しかなく、いまでも、var宣言のままの古いスクリプトをよく見かける。
var宣言すると、本来、その変数を使わない範囲(スコープ)でも変更・代入ができてしまい、エラーが出ない。これがバグの原因となり得るので、変数はできる限り let宣言を使ってブロックスコープで宣言することをおすすめする。

var2.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     //変数宣言
  23:     let a = 1;      //開始値
  24:     let b = 10;     //終了値
  25:     let n = 0;      //合計値
  26:     let s = '';     //計算式
  27:     let i = 100;    //関数スコープ内の変数
  28:     document.getElementById('let1').innerHTML = i;
  29: 
  30:     //aからbまでの整数の合計を求める
  31:     for (let i = ai <bi++) {   //forブロック内の変数
  32:         n +i;
  33:         s +i.toString();
  34:         //iが終了値でなければ計算式に+を追加する
  35:         if (i !b) {
  36:             s +'+';
  37:         }
  38:     }
  39:     document.getElementById('let2').innerHTML = s;
  40: 
  41:     document.getElementById('let3').innerHTML = i;
  42: }
  43: </script>

"var2.html" は、変数 i のスコープの違いを見るものだ。プログラムの流れは、「1.5 画面表示 - 計算式と計算結果を画面に表示」で作ったものと同じである。実行結果は次のようになる。
100
1+2+3+4+5+6+7+8+9+10
100
もし変数iが全て同じスコープとして扱われるなら、プログラムの最初で100を代入しているが、forループ内で最終的に10を代入するので、最後の表示は10となるはずだ。
実際には、for ループ内で let 宣言した変数 i はループのブロック内でしか通用しないので、その外側の関数内で let 宣言した変数 i には影響せず、上記のような結果となる。

このあと関数の説明をするが、異なる関数で同じ変数名を使うことがよくある。同じ名前の変数が影響し合わないように、そのスコープを明示的に宣言する習慣を身につけておこう。

変数の格納

実行中の変数の値はメモリ上で管理され、プログラムを終了すると原則として失われる。保存したいデータはファイルやデータベースなどへ書き出す必要がある。
変数がどのような形でメモリに格納されるかを知ることは、JavaScriptエンジンが変数をどのように扱うかを知る上で役に立つので、模式図を使って説明しよう。
JavaScriptエンジンとは、JavaScriptのプログラムを解釈・実行するアプリケーションのこと。たとえば Google Chromeや Edgeには V8 が、Safariには JavaScriptCore が、Firefoxには SpiderMonkey というJavaScriptエンジンが内蔵されている。
変数に値を代入
値2を用意する模式図
let i = 2;
この式は、変数 i に値 2 を代入するものだ。
ここでは理解しやすくするため、JavaScriptエンジン が値 2 を〈箱〉に格納する模式図で表す。実際の格納方法はエンジンの実装によって異なる。
変数に値を代入
変数iと値2の関係を示す模式図
代入演算子 = が実行されると、JavaScriptエンジン は変数 i が、上述の 2 を格納した〈箱〉を指すように紐付けする。
この〈箱〉は実際のメモリ・アドレスではなく、値と変数の関係を理解するための模式表現である。JavaScriptエンジン はOSから割り当てられたメモリを使い、JavaScriptから直接アドレスを操作させずに管理する。
変数に値を代入
変数iの値を使って変数jの値を求める模式図
let j = i + 3;
つづいて、この式を実行する。
上述のように、変数 i が紐付く〈箱〉には値 2 が格納されている。
あらたに値 3 が格納されている〈箱〉が用意され、加算演算子 + が実行されると、それぞれの〈箱〉から値をコピーして、計算を実行する。
結果の値 5 を〈箱〉に格納し、代入演算子 = が実行されると、JavaScriptエンジン は、それを変数 j に紐付ける。
変数に値を代入
変数iの値を使った計算の模式図
i = i + 3;
変数 i の値を使って計算し、その結果を再び自分自身に代入する操作を「自己代入」と呼ぶ。この計算を実行すると、i には元の 2 ではなく 5 が代入される。
加算演算子 + が実行された時点は、左図のような状態になる。これは上図で説明したとおりだ。
変数に値を代入
変数iへ計算結果を再代入する模式図
つづいて代入演算子 = が実行されると、JavaScriptエンジン は、変数 i の紐付け先を 2 から 5 へ切り替える。
こうして、変数 i の中身は 2 から 5 へと変わり、自己代入ができた。
ここで、以前に変数 i の値 2 が格納されていた〈箱〉が宙ぶらりんになる。つまり、自己代入を繰り返すとメモリ上に宙ぶらりんになった〈箱〉が無数にできることになる。これではいくらメモリを多く積んでも、メモリ不足に陥る恐れがある。
JavaScriptエンジンにはガーベジコレクション(GC)という仕組みが用意されており、プログラムで意識して書かなくても、不要になった〈箱〉を自動的に検出し、その〈箱〉を未使用状態に戻し、再利用できるようになっている。

練習問題:変数の格納のされ方

練習問題:ガベージコレクション

定数

JavaScriptでは、const宣言を使い、再代入できない変数を宣言できる。constはletと同じブロックスコープを持ち、宣言と同時に初期値が必要である。
変数と定数の違い
変数 何度でも値を代入できる。
定数 宣言時に初期値を代入し、その後は再代入できない。
物理定数やWeb APIのURLなど、参照先を変えない値は const で宣言すると、誤った再代入を防げる。ただし、constで宣言した配列やオブジェクトでも、その要素やプロパティは変更できる。constが防ぐのは変数そのものへの再代入である。

const1.html

  19: <script>
  20: //定数宣言
  21: const C0 = 299792458;       //真空中の光速(m/s)
  22: 
  23: /**
  24:  * 1光年を計算
  25:  * @const   C0
  26:  * @param   なし
  27:  * @return  float 1光年(km)
  28: */
  29: function lightYear() {
  30:     return C0 * 60 * 60 * 24 * 365.25 / 1000;
  31: }
  32: 
  33: //ページのロード時に実行
  34: window.onload = function() {
  35:     //変数宣言
  36:     let ly = lightYear();       //1光年(km)
  37: 
  38:     //結果を表示する
  39:     document.getElementById('C0').innerHTML = C0.toLocaleString();
  40:     document.getElementById('ly').innerHTML = ly.toLocaleString();
  41: }
  42: </script>

"const1.html" は、関数の外側で定数 C0(真空中の光速、単位はm/s)を宣言している。この定数はスクリプトのグローバルスコープを持つ。
関数 lightYear は、1年を365.25日とする定義に従って1光年を計算する。関数内でグローバル定数 C0 を参照している。

実行結果は次の通り。
真空中の光速=299,792,458 m/s
1光年=9,460,730,472,580.8 km


多くのプログラミング言語では円周率のような数学定数はあらかじめ用意されているが(JavaScriptでは Math.PI)、物理定数は用意されていないことが多い。自力で定数宣言する必要がある。

練習問題:定数

練習問題:再代入

コラム:命名規則

マイコンBASICマガジン
マイコンBASICマガジン
パソコン黎明期のBASICでは、変数名を長くすると実行速度が低下するということがあった。また、C言語では、タイピング量を減らすために省略語を使うことが多かった。(例:stoi = string to integer)
現代のプログラミング言語は、変数名長の影響を受けることはないので、あとでプログラムを読み返したときや、他人がプログラムを読んだときに分かりやすい、簡潔な名前を付けるようにしよう。

変数や関数の名前の付け方を命名規則(ネーミングルール)と呼ぶ。命名規則はプログラミング言語の文法ではないが、会社やプロジェクトチームで決めていることが多い。
よくある命名規則の骨子は以下の通りだ。
  • 自然な英語で書く。例:year(年)
  • 単語と単語の間をアンダースコアでつなぐスネークケース(例:light_year)と、2語目以降の先頭を大文字にするローワーキャメルケース(例:lightYear)がある。
  • 定数をすべて大文字のスネークケースにする規則(例:SPEED_OF_LIGHT)もよく使われる。
このシリーズでは、スネークケースで、グローバル変数は頭1文字を大文字という命名規則とする。

コラム:varを使わないもう1つの理由

var を使わない、もう1つ大きな理由がある。

var3.html

  22:     // varの場合
  23:     document.getElementById('let1').innerHTML = a;
  24:     var a = 10;
  25: 
  26:     // letの場合
  27:     document.getElementById('let2').innerHTML = b;
  28:     let b = 10;

プログラム "var3.html" を実行すると、var の方は、変数宣言していないにもかかわらず、画面に undefined と表示ができてしまう。一方、let の方は、画面には何も表示しないが、コンソールに変数宣言前に使ったというエラー表示がなされている。変数宣言しているのだから、動きとしては let の方が合目的である。
一方、var の方は、こうした動きに加え、何度でも var a; と宣言することができる。つまり、変数宣言する意味がほとんどないのである。
これが、var が使われなくなったもう1つの大きな理由である。

なお、JavaScriptでは、宣言がコード上の位置より前から存在するように見える動作をホイスティングと呼ぶ。varは宣言前に参照すると undefined になる。一方、letとconstはブロックの先頭から宣言行まで「一時的デッドゾーン」にあり、宣言前に参照すると ReferenceError になる。
関数宣言(function)については、プログラムの後方に書いた関数を、前方に書いたメイン・プログラムから呼び出すこともできるので、柔軟なプログラミングを可能にしている。

コラム:ミュータブルとイミュータブル

mutable.html

  20: <script>
  21: //ページのロード時に実行
  22: window.onload = function() {
  23:     // 代入
  24:     let a = [1, 2, 3];          // 配列a
  25:     let b = a;                  // 配列b
  26:     document.getElementById('arrayA1').innerHTML = a;
  27:     document.getElementById('arrayB1').innerHTML = b;
  28: 
  29:     // 比較演算
  30:     document.getElementById('aEQb1').innerHTML = (a === b);
  31: 
  32:     // ミュータブル
  33:     a[0] = 99;
  34:     document.getElementById('arrayA2').innerHTML = a;
  35:     document.getElementById('arrayB2').innerHTML = b;
  36: 
  37:     // 比較演算
  38:     document.getElementById('aEQb2').innerHTML = (a === b);
  39: }
  40: </script>

ミュータブル
ミュータブル
たとえばプログラム "mutable.html" では、変数 a に配列 [1, 2, 3] を代入し、続いて ba を代入する。配列はオブジェクトなので、aとbは同じ配列を参照する。図の300番地はこの共有関係を示す仮の番号であり、実際のメモリ・アドレスではない。

このため、[a0] = 99 として配列の先頭要素を変更すると、bから見える配列も変わる。このように内容を変更できる性質をミュータブル(変更可能)という。これは変数aへの再代入ではなく、配列要素の変更である。

厳密等価演算子 === を使ってみると、再代入の前後で ab の同一性が失われていないことが分かる。

immutable.html

  20: <script>
  21: //ページのロード時に実行
  22: window.onload = function() {
  23:     // 代入
  24:     let a = 1;          // 変数a
  25:     let b = a;          // 変数b
  26:     document.getElementById('varA1').innerHTML = a;
  27:     document.getElementById('varB1').innerHTML = b;
  28: 
  29:     // 比較演算
  30:     document.getElementById('aEQb1').innerHTML = (a === b);
  31: 
  32:     // イミュータブル
  33:     a = 99;
  34:     document.getElementById('varA2').innerHTML = a;
  35:     document.getElementById('varB2').innerHTML = b;
  36: 
  37:     // 比較演算
  38:     document.getElementById('aEQb2').innerHTML = (a === b);
  39: }
  40: </script>

イミュータブル
イミュータブル
プログラム "immutable.html" では、変数 a に数値1を代入し、続いて b にaの値を代入する。数値はプリミティブ値なので、bには値が渡される。図の400番地は説明用の模式表現であり、実際の格納方法を表すものではない。

その後、変数 a に99を再代入しても、変数 b の値は変化しない。数値そのものの内容は変更できず、新しい値を変数へ代入するためである。この性質をイミュータブル(変更不可)という。

厳密等価演算子 === を使ってみると、再代入の前後で ab の同一性が失われていることが分かる。
2.2 データ型」でJavaScriptの8つのデータ型を紹介するが、ここでは先行して、それぞれのデータ型がイミュータブルなのかミュータブルなのか、下表に整理しておこう。
種別No.データ型内  容変更可否
プリミティブ型 1Number数値(整数または小数)。イミュータブル
2String文字列。イミュータブル
3BigInt巨大整数。任意精度の整数値。
Number.MAX_SAFE_INTEGER(後述)より大きな数値を扱うことができる。
イミュータブル
4Boolean真偽値。true または falseイミュータブル
5nullnull 値を意味する特殊なキーワード。
JavaScript は大文字・小文字を区別するため、Null や NULL と同じではない。
イミュータブル
6undefined値が未定義。イミュータブル
7Symbolシンボル。ES2015以降の機能。イミュータブル
複合型 8Objectオブジェクト。ミュータブル

参考サイト

(この項おわり)
header