目次
サンプル・プログラム
変数と名前
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>
コメントアウトした変数 3hoge を実行しようとするとエラーになる。
たとえばGoogle Chromeでは、[F12]キーをクリックすると、下図のようにJavaScriptのエラーを表示するようになる。他のブラウザにも同様機能が備わっており、JavaScriptの簡易デバッガとして役立つだろう。
変数 _hoge1 を二度、使い回していることに注目してほしい。一度使った変数に別の値を代入することを再代入という。
再代入のときには let を使わない。let は変数を最初に使うときの宣言ととらえていただきたい。
練習問題:変数と名前
グローバル変数とローカル変数
var で宣言した変数は、関数の内側なら関数スコープ、関数の外側ならグローバルスコープを持つ。varはブロックスコープを持たない。
let と const で宣言した変数は、宣言したブロック内で通用するブロックスコープを持つ。
ブラウザでは 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 = a; i <= b; i++) { //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>
100もし変数iが全て同じスコープとして扱われるなら、プログラムの最初で100を代入しているが、forループ内で最終的に10を代入するので、最後の表示は10となるはずだ。
1+2+3+4+5+6+7+8+9+10
100
実際には、for ループ内で let 宣言した変数 i はループのブロック内でしか通用しないので、その外側の関数内で let 宣言した変数 i には影響せず、上記のような結果となる。
このあと関数の説明をするが、異なる関数で同じ変数名を使うことがよくある。同じ名前の変数が影響し合わないように、そのスコープを明示的に宣言する習慣を身につけておこう。
変数の格納
変数がどのような形でメモリに格納されるかを知ることは、JavaScriptエンジンが変数をどのように扱うかを知る上で役に立つので、模式図を使って説明しよう。
JavaScriptエンジンとは、JavaScriptのプログラムを解釈・実行するアプリケーションのこと。たとえば Google Chromeや Edgeには V8 が、Safariには JavaScriptCore が、Firefoxには SpiderMonkey というJavaScriptエンジンが内蔵されている。
let i = 2;この式は、変数 i に値 2 を代入するものだ。
ここでは理解しやすくするため、JavaScriptエンジン が値 2 を〈箱〉に格納する模式図で表す。実際の格納方法はエンジンの実装によって異なる。
この〈箱〉は実際のメモリ・アドレスではなく、値と変数の関係を理解するための模式表現である。JavaScriptエンジン はOSから割り当てられたメモリを使い、JavaScriptから直接アドレスを操作させずに管理する。
let j = i + 3;つづいて、この式を実行する。
上述のように、変数 i が紐付く〈箱〉には値 2 が格納されている。
あらたに値 3 が格納されている〈箱〉が用意され、加算演算子 + が実行されると、それぞれの〈箱〉から値をコピーして、計算を実行する。
結果の値 5 を〈箱〉に格納し、代入演算子 = が実行されると、JavaScriptエンジン は、それを変数 j に紐付ける。
i = i + 3;変数 i の値を使って計算し、その結果を再び自分自身に代入する操作を「自己代入」と呼ぶ。この計算を実行すると、i には元の 2 ではなく 5 が代入される。
加算演算子 + が実行された時点は、左図のような状態になる。これは上図で説明したとおりだ。
こうして、変数 i の中身は 2 から 5 へと変わり、自己代入ができた。
JavaScriptエンジンにはガーベジコレクション(GC)という仕組みが用意されており、プログラムで意識して書かなくても、不要になった〈箱〉を自動的に検出し、その〈箱〉を未使用状態に戻し、再利用できるようになっている。
練習問題:変数の格納のされ方
練習問題:ガベージコレクション
定数
| 変数 | 何度でも値を代入できる。 |
| 定数 | 宣言時に初期値を代入し、その後は再代入できない。 |
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>
練習問題:定数
練習問題:再代入
コラム:命名規則
現代のプログラミング言語は、変数名長の影響を受けることはないので、あとでプログラムを読み返したときや、他人がプログラムを読んだときに分かりやすい、簡潔な名前を付けるようにしよう。
変数や関数の名前の付け方を命名規則(ネーミングルール)と呼ぶ。命名規則はプログラミング言語の文法ではないが、会社やプロジェクトチームで決めていることが多い。
- 自然な英語で書く。例:year(年)
- 単語と単語の間をアンダースコアでつなぐスネークケース(例:light_year)と、2語目以降の先頭を大文字にするローワーキャメルケース(例:lightYear)がある。
- 定数をすべて大文字のスネークケースにする規則(例:SPEED_OF_LIGHT)もよく使われる。
コラム: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;
一方、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>
このため、[a0] = 99 として配列の先頭要素を変更すると、bから見える配列も変わる。このように内容を変更できる性質をミュータブル(変更可能)という。これは変数aへの再代入ではなく、配列要素の変更である。
厳密等価演算子 === を使ってみると、再代入の前後で a と b の同一性が失われていないことが分かる。
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>
その後、変数 a に99を再代入しても、変数 b の値は変化しない。数値そのものの内容は変更できず、新しい値を変数へ代入するためである。この性質をイミュータブル(変更不可)という。
厳密等価演算子 === を使ってみると、再代入の前後で a と b の同一性が失われていることが分かる。
| 種別 | No. | データ型 | 内 容 | 変更可否 |
|---|---|---|---|---|
| プリミティブ型 | 1 | Number | 数値(整数または小数)。 | イミュータブル |
| 2 | String | 文字列。 | イミュータブル | |
| 3 | BigInt | 巨大整数。任意精度の整数値。 Number.MAX_SAFE_INTEGER(後述)より大きな数値を扱うことができる。 | イミュータブル | |
| 4 | Boolean | 真偽値。true または false | イミュータブル | |
| 5 | null | null 値を意味する特殊なキーワード。 JavaScript は大文字・小文字を区別するため、Null や NULL と同じではない。 | イミュータブル | |
| 6 | undefined | 値が未定義。 | イミュータブル | |
| 7 | Symbol | シンボル。ES2015以降の機能。 | イミュータブル | |
| 複合型 | 8 | Object | オブジェクト。 | ミュータブル |
参考サイト
- ECMAScript Language Specification:Ecma International
- 文法とデータ型:MDN Web Docs
- メモリ管理:MDN Web Docs
- The International System of Units (SI Brochure):BIPM

JavaScriptの文法は、Ecma Internationalが ECMAScriptとして標準化している。
ここでは、クラスが利用できるようになったバージョン ES2015(ES6) (2015年6月)に則って説明する。
まず、変数と定数の宣言や名前、有効範囲(スコープ)について事例を交えながら説明しよう。