目次
サンプル・プログラム
変数と名前
JavaScriptの場合、半角英字、アンダースコア (_)、ドル記号 ($) から始まる文字で、続く文字には半角数字 (0–9) を使うことができる。英字は大文字と小文字を区別する。識別子の長さに制限はない。Unicode文字も使用できるとされているが、正常に動かないブラウザがあるので使用しない方がいい。半角数字から始めることができない点に注意。
プログラミング言語によって識別子の制限は異なるが、おおむねJavaScriptと同じと考えていい。
変数名は、誰でも分かるような読みやすいものにすべきだが、これについては「コラム:命名規則」をご覧いただきたい。
また、次の文字列はJavaScriptの予約語となっており、識別子(変数名や関数名)として使えない。背景色がライトブルーの予約語は、厳格モード等で使えないものを示します。
| 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 | 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 宣言した変数は、宣言した関数内またはプログラム全体(グローバルスコープ)で通用するグローバル変数(大域変数)になる。
let 宣言した変数は、宣言したブロック内(ブロックスコープ)で通用するローカル変数になる。
なお、JavaScriptでは 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++) { //ローカル変数
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エンジン が管理している仮想的なものととらえておいてほしい。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 / 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 光年)と頭1文字大文字にするキャメルケース(例:LightYear 光年)がある。
- グローバル変数は頭1文字を大文字にしたり(例:Speed_of_light 光速)、アンダースコアではじめる(例:_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, let, const)や関数宣言(function)が、実行される前にメモリに登録されるため、コード上で後ろに書いても、前で使えるように見えることがある。これをホイスティングと呼ぶ。
let と const はホイスティングするが、実行時に使えないようになっている。
関数宣言(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>
このため、変数 a の冒頭の値に 99 を再代入してやると、それに連動して変数 b の冒頭の値も変わる。これをミュータブル(変更可能)という。
厳密等価演算子 === を使ってみると、再代入の前後で 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 | オブジェクト。 | ミュータブル |

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