字句文法
このページでは、 JavaScript での字句文法を説明します。JavaScript のソーステキストは、単なる文字の列です。これをインタープリターに理解させるためには、文字列をより構造化された表現に解釈させる必要があります。構文解析の最初の手順は字句解析と呼ばれ、テキストを左から右へスキャンして、個々の原子的な入力要素の列に変換します。一部の入力要素はインタープリターにとって重要ではないので、この手順の後で取り除かれます。制御文字、行の終端文字、ホワイトスペース、コメントがそれに該当します。識別子や句読点などの他にも、更なる構文解析のために使用されます。 ECMAScript はまた、特定のキーワードとリテラルを定義し、特定の無効なトークン列を有効にするためにセミコロンを自動的に挿入する規則を持っています。
書式化制御文字
書式化制御文字は、視覚的表現を有していないものの、テキストの解釈を制御するために使用されます。
| コードポイント | 名前 | 略語 | 説明 |
|---|---|---|---|
| U+200C | Zero width non-joiner | <ZWNJ> | 特定の言語において、合字に接合されることを防ぐために、文字の間に配置されます。(Wikipedia) |
| U+200D | Zero width joiner | <ZWJ> | 特定の言語において、通常は接合されない文字を、接合した形を使用して文字を表示するために文字間に配置されます。 (Wikipedia) |
| U+FEFF | Byte order mark | <BOM> | 記述の先頭において、 Unicode を使用することと、そのテキストのバイト順をマークします。 (Wikipedia). |
JavaScriptのソーステキストでは、 <ZWNJ> と <ZWJ> は識別子部分として扱われ、 <BOM> (テキストの先頭にない場合はゼロ幅のノーブレークスペース <ZWNBSP> とも呼ばれます)は空白部分として扱われます。
ホワイトスペース
ホワイトスペースはソースのテキストの読みやすさを向上させ、トークンを互いに区別します。これらの文字は通常、コードの機能性には不要なものです。よく Minification tools を使用して、転送する必要があるデータの量を削減するためにホワイトスペースを除去します。
| コードポイント | 名前 | 略語 | 説明 | エスケープシーケンス |
|---|---|---|---|---|
| U+0009 | 文字単位のタブ | <TAB> | 水平タブ | \t |
| U+000B | 行単位のタブ | <VT> | 垂直タブ | \v |
| U+000C | フォームフィード | <FF> | 改ページの制御文字 (Wikipedia) | \f |
| U+0020 | 空白 | <SP> | 通常の空白 | |
| U+00A0 | ノーブレークスペース | <NBSP> | 通常の空白だが、改行を行ってよい位置ではない | |
| U+FEFF | ゼロ幅ノーブレークスペース | <ZWNBSP> | When not at the start of a script, the BOM marker is a normal whitespace character. | |
| Others | 他の Unicode の空白文字 | <USP> | "Space_Separator" 一般カテゴリーの文字 |
メモ: "White_Space" プロパティがあるが "Space_Separator" 一般カテゴリーにない文字のうち、 U+0009, U+000B, U+000C は JavaScript でもホワイトスペースとして扱われ、 U+0085 NEXT LINE は特別な役割を持たず、他にも改行文字の集合となるものがあります。
メモ: JavaScript エンジンで使用される Unicode 規格が変更されると、プログラムの動作に影響を与える可能性があります。例えば、 ES2016 では参照する Unicode 規格が 5.1 から 8.0.0 にアップグレードされ、その影響で U+180E MONGOLIAN VOWEL SEPARATOR が "Space_Separator" カテゴリから「書式化(Cf)」カテゴリに移動し、空白でなくなっています。その結果、" \u180E".trim().length の結果が 0 から 1 に変更されました。
改行文字
コメント
コメントは、ヒント、メモ、提案、警告を JavaScript のコードに追加するために使用されます。これにより、コードがより読みやすく、より理解しやすいものなります。また、コードが実行されないよう無効にするために使用することができます。これは、貴重なデバッグツールになることがあります。
JavaScript には、コード内にコメントを割り当てる方法が 2 つあります。
行コメント
1 番目の方法は // コメントです。つまり、これは同じ行にある、その後のすべてのテキストをコメントにします。例えば、
js
function comment() {
// This is a one line JavaScript comment
console.log('Hello world!');
}
comment();
ブロックコメント
2 番目の方法は /* */ スタイルで、もっとずっと柔軟なものです。
例えば、単一行に利用した場合は次のようになります。
js
function comment() {
/* This is a one line JavaScript comment */
console.log('Hello world!');
}
comment();
複数行のコメントも下記のように作成することができます。
js
function comment() {
/* This comment spans multiple lines. Notice
that we don't need to end the comment until we're done. */
console.log('Hello world!');
}
comment();
必要であれば、行の途中でコメントを使用することもできますが、これはコードが読みにくくなることがあるので注意が必要です。
js
function comment(x) {
console.log('Hello ' + x /* insert the value of x */ + ' !');
}
comment('world');
また、コードをコメントで囲むことで、コードが実行されないよう無効にすることができます。
js
function comment() {
/* console.log('Hello world!'); */
}
comment();
この場合、 console.log() の呼び出しはコメント内部にあるので、実行されることはありません。何行分のコードであっても、このようにして無効にすることができます。
ハッシュバンコメント
特別な 3 つ目のコメント構文としてハッシュバンコメントがあります。ハッシュバンコメントは、 #! で始まることと、スクリプトやモジュールの絶対的な開始位置でのみ有効であることを除いて、単一の行のみ (//) のコメントと全く同じように動作します。なお、 #! の前にはいかなる種類の空白も許されないことにも注意してください。コメントは #! 以降の最初の行の終わりまでのすべての文字で構成され、このようなコメントは 1 つだけ許可されます。
JavaScriptでのハッシュバンコメントは Unix におけるシバンに似ていて、スクリプトを実行するために使用したい特定の JavaScript インタープリターへのパスを指定します。ハッシュバンコメントが標準化される前に、 Node.js のようなブラウザー以外のホストではすでにデファクトとして実装されており、エンジンに渡される前にソーステキストから取り除かれるようになっていました。例として以下のようなものがあります。
js
#!/usr/bin/env node
console.log("Hello world");
JavaScript インタープリターはこれを通常のコメントとして扱います。スクリプトが直接シェルで実行された場合のみ、シェルに対して意味を持ちます。
警告: スクリプトをシェル環境で直接実行できるようにしたい場合は、 BOM のない UTF-8 でエンコードしてください。ハッシュバンコメントの前に BOM があってもブラウザーでは動作しますが、ハッシュバンのあるスクリプトで BOM を使用することは推奨されていません。 BOM は Unix/Linux のシェル環境でスクリプトを実行しようとすると動作しません。したがって、シェル環境から直接スクリプトを実行したい場合は BOM のない UTF-8 を使用してください。
#! の形のコメントは JavaScript インタープリターを指定するためにだけ使用してください。他の用途ではすべて // のコメント(または複数行コメント)を使用してください。
識別子
識別子 は、値と名前をリンクさせるために使用されます。識別子は様々な場所で使用することができます。
js
const decl = 1; // 変数宣言(`let` または `var` も可)
function fn() {} // 関数宣言
const obj = { key: 'value' }; // オブジェクトキー
class C { // クラス宣言
#priv = 'value'; // プライベートプロパティ
}
lbl: console.log(1); // ラベル
JavaScript では、識別子は一般的に英数字、アンダースコア (_)、ドル記号 ($) で構成されます。識別子は数字で始めることはできません。しかし、JavaScript で使用できる識別子は ASCII だけではなく、ほとんどの Unicode コードポイントも使用可能です。
メモ: もし何らかの理由で JavaScript のソースを自分で解析する必要がある場合、すべての識別子が /[A-Za-z_$][\w$]*/ のパターンに従っている(つまり ASCII のみ)と仮定しないでください。 識別子の範囲は正規表現 /[$_p{ID_Start}][$u200cu200dp{ID_Continue}]*/u (Unicodeエスケープシーケンスを除く) で記述することができます。
また、JavaScript では、識別子の中で Unicode エスケープシーケンスを \u0000 または \u{000000} という形式で使用することができ、これは実際の Unicode 文字と同じ文字列値をエンコードするものです。例えば、你好 と \u4f60\u597d は同じ識別子です。
js
const 你好 = "Hello";
console.log(\u4f60\u597d); // Hello
すべての場所で、すべての範囲の識別子が受け入れられるわけではありません。関数宣言、関数式、変数宣言などの特定の構文では、予約語でない識別子名を使用する必要があります。
js
function import() {} // 違反: import は予約語です。
最も注目すべきは、プライベートプロパティとオブジェクトプロパティは、予約語を許可していることです。
js
const obj = { import: "value" }; // `import` は予約語だが有効
class C {
#import = "value";
}
キーワード
キーワード は識別子のように見えますが、 JavaScript で特別な意味を持つトークンです。例えば、関数宣言の前のキーワード async は、その関数が非同期であることを示します。
キーワードの中には予約されているものがあり、変数宣言や関数宣言などの識別子として使用することができないことを意味します。これらはよく予約語と呼ばれます。予約語の一覧は下記に掲載されています。すべてのキーワードが予約されているわけではありません。例えば、 async はどこでも識別子として使用することができます。一部のキーワードは文脈的な予約語です。例えば、 await は非同期関数の本体でのみ、 let は厳格モードコード、または const および let 宣言でのみ予約されています。
識別子は常に 文字列値 で比較されるため、エスケープシーケンスは解釈されます。例えば、このような場合も構文エラーとなります。
js
const els\u{65} = 1;
// `els\u{65}` encodes the same identifier as `else`
予約語
これらのキーワードは、 JavaScript で変数、関数、クラスなどの識別子として使用することはできません。
breakcasecatchclassconstcontinuedebuggerdefaultdeletedoelseexportextendsfalsefinallyforfunctionifimportininstanceofnewnullreturnsuperswitchthisthrowtruetrytypeofvarvoidwhilewith
以下のものは、厳格モードのコードで使われた場合のみ予約語になります。
以下のものは、モジュールコードや非同期関数本体に現れた場合にのみ予約語になります。
今後の予約語
以下のものは、 ECMAScript の仕様によって今後のキーワードとして予約されています。これらは現時点では特別な機能を持っていませんが、将来は持つ可能性があるので、識別子として使用することはできません。
以下のものは常に予約されています。
enum
以下のものは、厳格モードで遭遇した場合のみ予約語になります。
implementsinterfacepackageprivateprotectedpublic
旧仕様にあった今後の予約キーワード
以前の ECMAScript の仕様書 (ECMAScript 1 から 3 まで) では、以下のものが将来のキーワードとして予約されています。
abstractbooleanbytechardoublefinalfloatgotointlongnativeshortsynchronizedthrowstransientvolatile
特別な意味を持つ識別子
一部の識別子は、キーワードでなくても、あるコンテキストで特別な意味を持つことがあります。それらは以下の通りです。
arguments(キーワードではありませんが、厳格モードでは識別子として宣言できません)as(import * as ns from "mod")asynceval(キーワードではありませんが、厳格モードでは識別子として宣言できません)from(import x from "mod")getofset
リテラル
Null リテラル
詳細については null をご覧ください。
js
null
論理値リテラル
詳細については論理型をご覧ください。
js
true
false
数値リテラル
数値型 (Number) および長整数型 (BigInt) が数値リテラルを使用します。
10 進数
js
1234567890
42
// 先頭にゼロがあるものを使用する場合は注意してください
0888 // 888 は 10 進数として解釈されます
0777 // 8 進数として解釈され、 10 進数では 511 です。
なお、 10 進数リテラルはゼロ (0) から始め、他の 10 進数の数字を続けることができますが、 0 に続く数字がすべて 8 より小さい場合は、その数値が 8 進数として解釈されることに注意してください。さらに、接頭辞 0 を持つ数値リテラルは、 8 進数として解釈しても 10 進数として解釈しても、厳格モードでは構文エラーが発生します。ですから、代わりに 0o 接頭辞を使用してください。
指数
10 進数の指数リテラルは、 beN の書式で指定します。ここで b は基数(整数または浮動小数点)、その後に e 文字(セパレーターまたは指数記号として機能)、そして N は指数またはべき乗数 - 符号付き整数です(2019 ECMA-262 仕様に従います)。
js
0e-5 // 0
0e+5 // 0
5e1 // 50
175e-2 // 1.75
1e3 // 1000
1e-3 // 0.001
1E3 // 1000
2 進数
2進数の構文は、先頭のゼロに続いて小文字または大文字のラテン文字 "B" を使用します (0b または 0B)。 0b の後の数字が 0 または 1 でない場合は、 SyntaxError が "Missing binary digits after 0b" の内容で発生します。
js
const FLT_SIGNBIT = 0b10000000000000000000000000000000; // 2147483648
const FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040
const FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607
8 進数
8進数の構文は、先頭のゼロに続いて小文字または大文字のラテン文字 "O" を使用します (0o または 0O)。 0o の後の数字が範囲 (01234567) 外の場合、 SyntaxError が "Missing octal digits after 0o" の内容で発生します。
js
const n = 0O755; // 493
const m = 0o644; // 420
16 進数
16 進数の構文は、先頭のゼロに続いて小文字または大文字のラテン文字 "X" を使用します (0x または 0X)。 0x の後の数字が範囲 (0123456789ABCDEF) 外の場合、 SyntaxError が "Identifier starts immediately after numeric literal" の内容で発生します。
js
0xFFFFFFFFFFFFFFFFF // 295147905179352830000
0x123456789ABCDEF // 81985529216486900
0XA // 10
長整数リテラル
長整数型 (BigInt) は JavaScript の数値プリミティブであり、自由な精度の整数を表すことができます。長整数リテラルは、整数の末尾に n を追加することで作成されます。
js
123456789123456789n // 123456789123456789
0o777777777777n // 68719476735
0x123456789ABCDEFn // 81985529216486895
0b11101001010101010101n // 955733
なお、先頭がゼロだけの 8 進数は BigInt では動作しません。
js
0755n
// SyntaxError: invalid BigInt syntax
8 進数の BigInt 数値では、常にゼロの後に "o" (大文字でも小文字でも) を付けて使用してください。
js
0o755n
BigInt についての詳細な情報は、 JavaScript のデータ構造をご覧ください。
数値の区切り文字
数値リテラルの可読性を高めるために、アンダースコア (_, U+005F) を区切り文字として使用することができます。
js
// 10 進数の区切り文字
1_000_000_000_000
1_050.95
// 2 進数の区切り文字
0b1010_0001_1000_0101
// 8 進数の区切り文字
0o2_2_5_6
// 16 進数の区切り文字
0xA0_B0_C0
// BigInt の区切り文字
1_000_000_000_000_000_000_000n
なお、以下の制限があります。
js
// 連続して 2 つ以上のアンダースコアは許可されていません
100__000; // SyntaxError
// 数値リテラルの末尾に置くことは許可されていません
100_; // SyntaxError
// 先頭の 0 の後に使用することはできません
0_1; // SyntaxError
オブジェクトリテラル
詳細については、 Object とオブジェクト初期化子をご覧ください。
js
const o = { a: 'foo', b: 'bar', c: 42 };
// 短縮記法
const a = 'foo', b = 'bar', c = 42;
const o = { a, b, c };
// 以前の表記
const o = { a: a, b: b, c: c };
配列リテラル
詳細については Array をご覧ください。
js
[1954, 1974, 1990, 2014]
文字列リテラル
文字列リテラルは、単一引用符または二重引用符に囲まれた零個以上の Unicode コードポイントです。 Unicode コードポイントはエスケープシーケンスで表すこともできます。以下の引用符を閉じるコードポイントを除いて、すべてのコードポイントが文字列リテラルに現れることができます。
- U+005C \ (バックスラッシュ)
- U+000D <CR>,
- and U+000A <LF>.
すべてのコードポイントが、エスケープシーケンスの形で現れることができます。文字列リテラルは ECMAScript の文字列値として評価されます。これらの文字列の値を生成する際に、 Unicode コードポイントは UTF-16 エンコードされます。
js
'foo';
"bar";
16 進エスケープシーケンス
16 進エスケープシーケンスは \x に続いてちょうど 2 桁の 16 進数から成り、 0x0000 から 0x00FF までのコード単位またはコードポイントを表します。
js
'\xA9' // "©"
Unicode エスケープシーケンス
Unicode エスケープシーケンスは \u に続いてちょうど 4 桁の 16 進数から成ります。これで UTF-16 エンコーディングのコード単位を表します。コードポイント U+0000 から U+FFFF までは、コード単位とコードポイントは等しくなります。コードポイント U+10000 から U+10FFFF までは、 2 つのエスケープシーケンスで 2 つのコード単位 (サロゲートペア) を表す必要があります。サロゲートペアはコードポイントで区別されます。
See also String.fromCharCode() and String.prototype.charCodeAt().
js
'\u00A9' // "©" (U+A9)
Unicode コードポイントエスケープ
Unicode コードポイントエスケープは \u{ に続いて 16 進数のコードポイントが続き、 } が続きます。 16 進数の値は 0 から 0x10FFFF までの範囲に含まれている必要があります。 U+10000 から U+10FFFF までの範囲のコードポイントを、サロゲートペアとして表す必要はありません。
String.fromCodePoint() または String.prototype.codePointAt() もご覧ください。
js
'\u{2F804}' // CJK COMPATIBILITY IDEOGRAPH-2F804 (U+2F804)
// 同じ文字をサロゲートペアで表したもの
'\uD87E\uDC04'
正規表現リテラル
詳細については RegExp を参照してください。
js
/ab+c/g;
// 「空の」正規表現リテラル
// 単一行コメントと区別するために、空のキャプチャしない
// グループが必要です。
/(?:)/;
テンプレートリテラル
詳細について、テンプレート文字列をご覧ください。
js
`string text`
`string text line 1
string text line 2`
`string text ${expression} string text`
tag `string text ${expression} string text`
自動セミコロン挿入
一部の JavaScript 文はセミコロンで終わる必要があります。したがって、自動セミコロン挿入 (ASI) の影響を受けます。
let,const, 変数定義import,export, モジュール宣言- 式の文
debuggercontinue,break,throwreturn
セミコロンが自動的に挿入されるケースは 3 つあります。
1. 文法上許されないトークンに出会ったとき、それが前のトークンから少なくとも 1 つの改行文字で区切られているか、そのトークンが "}" であれば、その前にセミコロンが挿入されます。
js
{ 1
2 } 3
// 上記の文は、 ASI によって次のように変換されます
{ 1
;2 ;} 3;
// 3 つの文をエンコードする正しい文法で、
// それぞれが数値リテラルで構成されています
do...while の末尾の ")" は、このルールでも特別なケースとして扱われます。
js
do {
// ...
} while (condition) /* ; */ // ここで ASI
const a = 1
2. トークンの入力ストリームの末尾が検出され、パーサーが単一の入力ストリームを完全なプログラムとして解釈できない場合、末尾にセミコロンが挿入されます。
js
const a = 1 /* ; */ // ASI here
このルールは前回のルールを補完するもので、特に「問題のあるトークン」がなく、入力ストリームが終わっている場合を想定しています。
3. 文法上で改行が禁止されている場所で改行が見つかった場合は、セミコロンを挿入します。このような場所は、以下の通りです。
式 <ここ> ++,式 <ここ> --continue <ここ> ラベルbreak <ここ> ラベルreturn <ここ> 式throw <ここ> 式yield <ここ> 式yield <ここ> * 式(param) <ここ> => {}async <ここ> function,async <ここ> prop(),async <ここ> function*,async <ここ> *prop(),async <ここ> (param) <ここ> => {}
ここで ++ は、変数 b に適用される後置演算子としては扱われません。というのも、改行文字が b と++ の間にあるからです。
js
a = b
++c
// 上記の文は、 ASI によって次のように変換されます
a = b;
++c;
ここでは、 return 文は undefined を返し、 a + b は到達できない文になります。
js
return
a + b
// 上記の文は、 ASI によって次のように変換されます
return;
a + b;
ASI は、改行がなければ無効な構文を生成するようなトークンを区切った場合にのみ発生することに注意してください。次のトークンが有効な構文の一部として解釈できる場合は、セミコロンは挿入されません。例えば、
js
const a = 1
(1).toString()
const b = 1
[1, 2, 3].forEach(console.log)
() は関数呼び出しと見なせるので、通常は ASI が発生しないでしょう。同様に、 [] はメンバーアクセスである可能性があります。上のコードは次のものと同等です。
js
const a = 1(1).toString()
const b = 1[1, 2, 3].forEach(console.log)
そのため、コードを実行すると "1 is not a function" や "Cannot read properties of undefined (reading 'forEach')" などのエラーが発生することになります。
クラス内では、クラスフィールドやジェネレーターメソッドも落とし穴になることがあります。
js
class A {
a = 1
*gen() {}
}
これは次のようになります。
js
class A {
a = 1 * gen() {}
}
したがって、 { のあたりで構文エラーになります。
セミコロンなしのスタイルを強制したい場合、 ASI を扱う上で以下のような経験則があります。
- 後置
++および--は、オペランドと同じ行に書く。 return、throw、yieldの後の式はキーワードと同じ行に置く。- 同様に、
breakまたはcontinueの後のラベルはキーワードと同じ行に置く。 - アロー関数の
=>は引数の末尾と同じ行に置く。 - 非同期関数やメソッドの
asyncの直後で改行しない。 - 行が
(,[,`,+,-,/(正規表現リテラル) で始まる場合は、直前にセミコロンを置くか、前の行の行末にセミコロンをつける。 - クラスのフィールドは、できれば常にセミコロンで終わるようにします。一つ前のルール(フィールド宣言の後に計算されたプロパティが続くと、その後は
[で始まる)に加えて、セミコロンはフィールド宣言とジェネレーターメソッドの間にも必要です。
ブラウザーの互換性
BCD tables only load in the browser