再入門JavaScript: 字句構造、型・リテラル

(2002.1.3) 新規作成.
(2007.1.27) 加筆し、ページを独立。
(2017.7.23) 全体的に、現代的な内容にupdate.

JavaScript / ECMAScriptのオブジェクトシステム、言語仕様など。すでに何らかのプログラミング言語が分かっている人が、手早くJavaScriptを理解するための手引きとして。

仕様

ECMAScript 3rd edition (1999年12月) が言語仕様を定めていた。4th は結局、まとまらなかった。次の5th edition は 2009年12月に発行され、実に10年ぶりの更新になった。

2017年7月現在の最新は、6月に出たばかりの 8th edition (ECMAScript 2017).

Webブラウザやサーバ環境、コンパイラでの実装状況は、次のページで分かる。

ECMAScript 6 (ES6; または ECMAScript 2015) は、Konqueror 4.14, IE 11 がまるっきり実装できていない。トランスコンパイラ Babel での変換も、確実にカバーされているわけではない。したがって、まだ、バリバリに使うには早い。

一方、ECMAScript 5は、ほとんどのWebブラウザ、サーバで、ほぼ完全に実装されている。今回は、ECMAScript 5をベースに解説を更新してみる。

字句構造

JavaScriptのスクリプトの文字コードはUnicode (規格ではUTF-16と書いているが、UTF-8でも問題ない。) で書くことになっている。が、HTMLに埋め込むなら地のHTMLと同じ文字コードにするしかない。

コメント

コメントは次の2種類。

  1. 複数行コメント. 「/*」から「*/」まで。入れ子にはできない。
  2. 単一行コメント. 「//」から行末まで. 文法が正規表現リテラルと曖昧だが、どちらとも解釈できる場合は, 単一行コメントが優先される。正規表現にするときは適宜エスケープが必要。

セミコロンの自動挿入

JavaScriptの文は「;」(セミコロン)で区切る。正しくは, 文はセミコロンで終わる (文の一部)。

しかし、セミコロンが必要な箇所に存在しなくても, エラーにならない場合がある。JavaScript のおせっかい機能で、行末にセミコロンがないときは、文脈から次の行に続いていることが明らかな場合を除き、セミコロンが自動的に挿入される (automatic semicolon insertion)。

JavaScript
[POPUP]
  1. "use strict";
  2. function x() {
  3. return
  4. 1;
  5. }
  6. document.write( x() ); // => undefined
JavaScript
[POPUP]
  1. function x() {
  2. return 1 + // 明らかに継続行
  3. 1;
  4. }
  5. document.write(x()); // 2

上の例のように, returnの直後の改行など、文が継続していると解釈できる場合であっても、自動セミコロン挿入されてしまう。意図していない場合があり、まったくよくない機能。しかし、過去との互換性のため, strictモードでも行われる。

strictモード

strictモードは, JavaScript の悪い慣習を, 意図してエラーにする。新しいコードを書く場合、常に有効にすべき。

スクリプトファイル全体または個別の関数単位で適用できる。フレームワークが出力時にファイルを連結するなどで, non-strict なコードが混ざる場合は関数単位で有効にし、そうでない場合はファイル全体で有効にする。

ファイル全体に適用するには、ファイルの冒頭に、"use strict"; と書く。

JavaScript
[POPUP]
  1. "use strict";
  2. // strictモードではエラー
  3. //v = "hi!";
  4. var v = "hi!";

関数単位は、関数の冒頭で同様に書く。

JavaScript
[POPUP]
  1. function strict() {
  2. "use strict";
  3. var v = 12;
  4. }
  5. strict();
  6. function nonStrict() {
  7. // this function is non-strict
  8. w = 34;
  9. }
  10. nonStrict();

識別子

識別子は次のとおり。アルファベットの大文字・小文字は区別される。関数名などに仮名・漢字も使える(が変態的)。

IdentifierName
IdentifierStart IdentifierPart*
IdentifierStart
UnicodeLetter | $ | _ | \ UnicodeEscapeSequence
IdentifierPart
IdentifierStart | UnicodeCombiningMark | UnicodeDigit | UnicodeConnectorPunctuation | <ZWNJ> | <ZWJ>

上の構文には「Unicode何とか」というのが出てくる。それぞれ、Unicode分類の次の文字が該当する;

UnicodeLetter Uppercase letter (Lu), Lowercase letter (Ll), Titlecase letter (Lt), Modifier letter (Lm), Other letter (Lo), Letter number (Nl)
UnicodeCombiningMark Non-spacing mark (Mn), Combining spacing mark (Mc)
UnicodeDigit Decimal number (Nd)
UnicodeConnectorPunctuation Connector punctuation (Pc)
JavaScript
[POPUP]
  1. function 関数() {
  2. AA = 10; aa = 20;
  3. document.write('日本語', AA);
  4. }
  5. 関数();

実行結果:

日本語10

キーワード

5th edition のキーワード (keyword) は次のものがある。プロパティ名、メソッド名、変数名などには使えない。

break case catch continue debugger default delete do else false finally for function if in instanceof new null return switch this throw true try typeof var void while with

キーワードとは別に, 将来の拡張のために予約された識別子 (future reserved word) がある。これらは, strictモードでは, キーワードと同様に、変数名などには使えない。エラーになる。non-strictモードでは、変数名などとして使うことができる。

8th edition までに次がキーワードに追加されているため、non-strictモードであっても, これらはプロパティ名などに使うべきではない。

await class const export extends import let static super yield

8th edition では、さらに次の識別子が予約されている。

enum implements interface package private protected public

型、リテラル

型 (type)

JavaScriptは prototype-based のオブジェクト指向プログラミング言語で、通常思い描くようなクラスはない。Javaなどは, 対照的に, class-based のオブジェクト指向言語。

JavaScript にも「型」(type) はある。しかし、JavaScript の型システムは完全に壊れている。ECMAScriptには次の6つの型がある;

  1. Undefined型 (Undefined type)
  2. Null type
  3. 真偽値型 (Boolean type)
  4. 文字列型 (String type)
  5. 数値型 (Number type) -- 整数と実数の区別はない.
  6. Object

次のコードで、各オブジェクトの型 type と、プロトタイプ名 (いわゆるクラス) を表示してみる。

JavaScript
[POPUP]
  1. "use strict";
  2. function write_type(v) {
  3. // 型を得る
  4. document.write( v, " : ", typeof v );
  5. // プロトタイプを得る
  6. var klass = Object.prototype.toString.call(v).slice(8, -1);
  7. document.write( ", ", klass );
  8. document.write("<br />\n");
  9. }
typeof obj いわゆるクラス 備考
null object Null typeは'object'.
true boolean Boolean
new Boolean(true)object Boolean boxingすると'object'
undefined undefined Undefined
1.1 number Number
new Number(1.2) object Number
'foo' string String
new String("bar")object String
/[0-9]/ object RegExp
new RegExp("abc")object RegExp
{f:1} object Object
[1, 2] object Array
new Array(1, 2) object Array
function () {} function Function 特別扱い. callメソッドを持つオブジェクト
new Function("") function Function
new Date() object Date
new Error() object Error
自作クラス object Object

上で JavaScript には 6つの型があると書いたが、実際の typeof obj の値はそれと整合していない。また, boxing されたオブジェクトを与えると, 'object' になってしまう。何なんだ。

ECMAScript 5までは, 次の組み込みクラスに限って、いわゆるクラス名を取得できる。それ以外は自作クラスも含め 'Object' で固定。変更する手段はない。

"Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", "String"

ECMAScript 6以降であれば、次のようにして Object.prototype.toString.call()[object クラス名] が返るようにできる。See Is there a way to change the internal [[Class]] property of a JavaScript Object? - Stack Overflow

JavaScript
[POPUP]
  1. // コンストラクタ
  2. function MyClass() { }
  3. // Object.prototype.toString.call() 対応
  4. MyClass.prototype[Symbol.toStringTag] = 'MyClass'; // ECMAScript 6拡張
  5. // オブジェクトを生成
  6. var obj = new MyClass();

Undefined型

未定義 (未初期化) を表す型。なお、変数を宣言せずに使用すると, undefined ではなくエラーになる。

undefined は、読み取り専用の識別子。

JavaScript
[POPUP]
  1. var y;
  2. document.write(y); // => undefined
  3. document.write(x); // Error: x is not defined

Null型

ナル値を表す型。リテラルは null

JavaScript
[POPUP]
  1. x = 10;
  2. x = null;
  3. document.write(x); // => null

真偽値型

ほかのメジャーなプログラミング言語と同様、JavaScriptでも二値で真偽を表す。0, '0'は偽になる。

リテラルは true または false. 真偽値の代表。

==演算子による比較では, 型変換が行われるため, trueと比較してもよい。珍しい。

JavaScript
[POPUP]
  1. function is_true(x, b) { document.write(x == b, "\n"); }
  2. is_true(1, true); // => true
  3. is_true(0, true); // => false
  4. is_true('0', true); // => false
  5. is_true(1, false); // => false
  6. is_true(0, false); // => true
  7. is_true('0', false); // => true

数値型

●●後で書く。

文字列型

単一の文字を表す文字型はない。文字列を表す string 型のみ。文字列はimmutable object。

文字列リテラルは,ダブルクォーテーションかシングルクォーテーションで囲む。どちらで囲んでも扱いに違いはない。えー。

文字列のなかで, \の直後に改行で、文字列を継続する。

エスケープシーケンスは次のいずれか;

エスケープシーケンス説明
\' '
\" "
\\ \ 自身
\b
\f
\n 改行文字 (LF) \u000a
\r 復帰文字 (CR) \u000d
\t 文字タブ文字 (HT) \u0009
\v
\xhh 16進数表記。hは2桁固定で,0〜9,a〜f,A〜F
\udddd UTF-16 の Unicode表記。dは4桁固定で,0〜9,a〜f,A〜F. surrogate pair は, UCS-4 にせずに, 分けて表記する。えー?

正規表現リテラル

/」で囲んだ部分は正規表現リテラルになる。RegExpクラスのオブジェクトが生成される。Ruby と似ている。

構文が除算と曖昧。//= は、文脈によって判断される。

単一行コメントと曖昧。空の正規表現を生成したいときは, /(?:)/とする。

オブジェクトリテラル

配列

●●後で書く。