第7章 JavaScriptの構文
目次
本書のご購入
(広告です。ブロックしないでください。)

第7章 JavaScriptの構文

JavaScriptの構文は比較的単純です。本章では、注意すべき点を説明します。

構文の概要

このセクションでは、JavaScriptの構文がどのようなものか、簡単に説明します。

以下は、5つの基本的な値の種類です。

  • ブール値

    true
    false
  • 数値

    1023
    7.851
  • 文字列

    'hello'
    "hello"
  • プレーンオブジェクト:

    {
        firstName: 'Jane',
        lastName: 'Doe'
    }
  • 配列

    [ 'apple', 'banana', 'cherry' ]

基本的な構文の例をいくつか示します。

// Two slashes start single-linecomments

var x;  // declaring a variable

x = 3 + y;  // assigning a value to the variable `x`

foo(x, y);  // calling function `foo` with parameters `x` and `y`
obj.bar(3);  // calling method `bar` of object `obj`

// A conditional statement
if (x === 0) {  // Is `x` equal to zero?
    x = 123;
}

// Defining function `baz` with parameters `a` and `b`
function baz(a, b) {
    return a + b;
}

等号の2つの異なる用法に注意してください。

  • 単一の等号(=)は、変数に値を代入するために使用されます。
  • 3つの等号(===)は、2つの値を比較するために使用されます(等号演算子を参照)。

コメント

コメントには2種類あります。

式と文

このセクションでは、JavaScriptにおける重要な構文上の違い、つまり式と文の違いについて見ていきます。

おおよそ、はアクションを実行します。ループとif文は、文の例です。プログラムは基本的に文のシーケンスです。[8]

JavaScriptが文を期待する場所では、式も記述できます。このような文は、式文と呼ばれます。逆は成り立ちません。JavaScriptが式を期待する場所に文を記述することはできません。たとえば、if文を関数の引数にすることはできません。

2種類の式は文のように見えます。構文カテゴリに関して曖昧です。

解析中の曖昧さを防ぐために、JavaScriptではオブジェクトリテラルと関数式を文として使用できません。つまり、式文は次で始まることはできません。

  • 中括弧
  • キーワードfunction

式がこれらのトークンのいずれかで始まる場合、式コンテキストでのみ表示できます。たとえば、式を括弧で囲むことで、この要件を満たすことができます。次に、それが必要な2つの例を見ていきます。

eval()によるオブジェクトリテラルの評価

evalは、文コンテキストでその引数を解析します。evalがオブジェクトを返すようにするには、オブジェクトリテラルを括弧で囲む必要があります。

> eval('{ foo: 123 }')
123
> eval('({ foo: 123 })')
{ foo: 123 }

関数の即時呼び出し式

以下のコードは、関数の即時呼び出し式(IIFE)です。これは、その本体がすぐに実行される関数です(IIFEの用途については、IIFEによる新しいスコープの導入で説明します)。

> (function () { return 'abc' }())
'abc'

括弧を省略すると、構文エラーが発生します。JavaScriptは関数宣言と見なすため、匿名にすることはできません。

> function () { return 'abc' }()
SyntaxError: function statement requires a name

名前を追加した場合も構文エラーが発生します。関数宣言は即時呼び出しできないためです。

> function foo() { return 'abc' }()
SyntaxError: Unexpected token )

関数宣言の後に続くものは、合法的な文でなければならず、()ではありません。

制御フロー文とブロック

制御フロー文の場合、本体は単一の文です。2つの例を以下に示します。

if (obj !== null) obj.foo();

while (x > 0) x--;

ただし、任意の文は、常にブロック(中括弧)で置き換えることができます。0個以上の文を含みます。したがって、次のように記述することもできます。

if (obj !== null) {
    obj.foo();
}

while (x > 0) {
    x--;
}

後者の制御フロー文の形式を好みます。標準化することで、単一文の本体と複数文の本体に違いがなくなります。その結果、コードはより一貫性のあるものになり、1つの文と複数の文の切り替えが容易になります。

セミコロンの使用規則

このセクションでは、JavaScriptにおけるセミコロンの使用方法について調べます。基本的な規則は以下のとおりです。

  • 通常、文はセミコロンで終了します。
  • 例外は、ブロックで終わる文です。

JavaScriptではセミコロンは省略可能です。省略されたセミコロンは、いわゆる自動セミコロン挿入(ASI;自動セミコロン挿入を参照)によって追加されます。ただし、この機能は常に期待通りに動作するとは限らないため、常にセミコロンを含める必要があります。

ブロックで終わる文の後にはセミコロンを付けない

以下の文は、ブロックで終わる場合、セミコロンで終了しません。

  • ループ:forwhile(ただしdo-whileは除く)
  • 分岐:ifswitchtry
  • 関数宣言(ただし関数式は除く)

以下はwhiledo-whileの例です。

while (a > 0) {
    a--;
} // no semicolon

do {
    a--;
} while (a > 0);

以下は関数宣言と関数式の例です。後者はセミコロンで終わります。これはvar宣言(これはセミコロンで終了する)の中に現れるためです。

function foo() {
    // ...
} // no semicolon

var foo = function () {
    // ...
};

注記

ブロックの後にセミコロンを追加しても、構文エラーは発生しません。空文と見なされるためです(次のセクションを参照)。

ヒント

セミコロンについて知っておく必要があるのは、ほとんどこれだけです。常にセミコロンを追加すれば、このセクションの残りの部分を読む必要はないでしょう。

空文

単独のセミコロンは空文であり、何も行いません。空文は、文が期待される場所にどこでも表示できます。文が必要だが不要な状況で役立ちます。そのような状況では、ブロックも通常許可されます。たとえば、次の2つの文は同等です。

while (processNextItem() > 0);
while (processNextItem() > 0) {}

関数processNextItemは、残りのアイテム数を返すものと想定されています。3つの空文で構成される次のプログラムも、構文的に正しくなります。

;;;

自動セミコロン挿入

自動セミコロン挿入(ASI)の目標は、行末のセミコロンを省略可能にすることです。自動セミコロン挿入という用語が呼び起こすイメージは、JavaScriptパーサーがユーザーのためにセミコロンを挿入することです(内部的には、通常は異なる方法で処理されます)。

言い換えれば、ASIはパーサーが文の終了を判断するのに役立ちます。通常、文はセミコロンで終了します。ASIは、文が次の場合にも終了すると規定しています。

  • 行終端子(例:改行)の後に、不正なトークンが続きます。
  • 閉じ括弧が検出されます。
  • ファイルの終わりに達しました。

例:不正なトークンによるASI

以下のコードには、行終端子に不正なトークンが続くものがあります。

if (a < 0) a = 0
console.log(a)

トークンconsole0の後に不正であり、ASIをトリガーします。

if (a < 0) a = 0;
console.log(a);

例:閉じ括弧によるASI

以下のコードでは、括弧内の文はセミコロンで終了していません。

function add(a,b) { return a+b }

ASIは、上記のコードの構文的に正しいバージョンを作成します。

function add(a,b) { return a+b; }

落とし穴:ASIは予期せず文を分割する可能性があります

ASIは、キーワードreturnの後に行終端子がある場合にもトリガーされます。例:

// Don't do this
return
{
    name: 'John'
};

ASIは上記を次のように変換します。

return;
{
    name: 'John'
};

これは、空のreturnに、ラベルnameが前にある式文'John'を含むブロックが続くものです。ブロックの後に、空文があります。

落とし穴:ASIは予期せずトリガーされない可能性があります

改行で始まる文が、前の文の続きとして許容されるトークンで始まる場合があります。その場合、ASIはトリガーされません。一見トリガーされそうに見えますが、そうではありません。例:

func()
[ 'ul', 'ol' ].forEach(function (t) { handleTag(t) })

2行目の角括弧は、func()によって返された結果へのインデックスとして解釈されます。括弧内のカンマは、カンマ演算子(この場合は'ol'を返します。詳細はカンマ演算子を参照)として解釈されます。そのため、JavaScriptは次のコードとして認識します。

func()['ol'].forEach(function (t) { handleTag(t) });

有効な識別子

識別子は、物事に名前を付けるために使用され、JavaScriptの様々な構文上の役割で現れます。例えば、変数名や引用符なしのプロパティキーは、有効な識別子である必要があります。識別子は大文字と小文字を区別します。

識別子の最初の文字は、次のいずれかです。

後続の文字は、次のとおりです。

有効な識別子の例

var ε = 0.0001;
var строка = '';
var _tmp;
var $foo2;

これにより、JavaScriptコードで様々な言語を使用できるようになりますが、識別子とコメントの両方について、英語を使用することをお勧めします。これにより、コードをできるだけ多くの人に理解してもらうことができ、今日の国際的なコードの普及状況を考えると重要です。

次の識別子は予約語です。これらは構文の一部であり、変数名(関数名やパラメータ名を含む)として使用することはできません。

arguments

break

case

catch

class

const

continue

debugger

default

delete

do

else

enum

export

extends

false

finally

for

function

if

implements

import

in

instanceof

interface

let

new

null

package

private

protected

public

return

static

super

switch

this

throw

true

try

typeof

var

void

while

次の3つの識別子は予約語ではありませんが、予約語として扱うべきです。

Infinity

NaN

undefined

最後に、標準的なグローバル変数の名前も避けるべきです(第23章を参照)。ローカル変数として使用しても問題はありませんが、コードが分かりにくくなります。

予約語は、引用符なしのプロパティキーとして使用できます(ECMAScript 5以降)。

> var obj = { function: 'abc' };
> obj.function
'abc'

識別子の正確なルールについては、Mathias Bynensのブログ記事“Valid JavaScript variable names”を参照してください。

ECMAScript 5には、よりクリーンなJavaScript、安全性の低い機能の削減、警告の増加、より論理的な動作をもたらす厳格モードがあります。通常の(非厳格)モードは、しばしば「寛容モード」と呼ばれます。

JavaScriptファイルの先頭または<script>要素の内部に次の行を入力することで、厳格モードをオンに切り替えます。

'use strict';

ECMAScript 5をサポートしていないJavaScriptエンジンは、この文を無視します。文字列をこのように(式文として。詳細はを参照)記述すると、通常は何も行われません。

関数ごとに厳格モードをオンにすることもできます。その場合は、関数を次のように記述します。

function foo() {
    'use strict';
    ...
}

これは、厳格モードをすべてに適用すると問題が発生する可能性のあるレガシーコードベースを操作する場合に便利です。

一般的に、厳格モードによって有効になる変更はすべて改善のためのものです。そのため、記述する新しいコードには厳格モードを使用することを強くお勧めします。ファイルの先頭に切り替えるだけです。ただし、2つの注意点があります。

既存のコードに対して厳格モードを有効にすると、コードが壊れる可能性があります。
コードが、もはや使用できない機能に依存している可能性があります。または、寛容モードと厳格モードで動作が異なる可能性があります。寛容モードのファイルに単一の厳格モード関数を追加するオプションがあることを忘れないでください。
慎重なパッケージ化
ファイルを連結および/または縮小する場合、厳格モードがオフになるべき場所でオフになっていないか、逆にオンになるべき場所でオンになっていないか注意する必要があります。両方ともコードを壊す可能性があります。

以降のセクションでは、厳格モードの機能について詳しく説明します。ほとんどの場合、そもそも行ってはいけないことについての警告が増えるだけなので、通常は知る必要はありません。

厳格モードは、関数関連の機能を制限します。

非メソッド関数ではthisはundefined

寛容モードでは、非メソッド関数のthisの値はグローバルオブジェクト(ブラウザではwindowグローバルオブジェクトを参照)です。

function sloppyFunc() {
    console.log(this === window);  // true
}

厳格モードでは、undefinedです。

function strictFunc() {
    'use strict';
    console.log(this === undefined);  // true
}

これはコンストラクタに役立ちます。例えば、次のコンストラクタPointは厳格モードです。

function Point(x, y) {
    'use strict';
    this.x = x;
    this.y = y;
}

厳格モードのため、誤ってnewを忘れ、関数として呼び出すと警告が表示されます。

> var pt = Point(3, 1);
TypeError: Cannot set property 'x' of undefined

寛容モードでは、警告が表示されず、グローバル変数xyが作成されます。詳細はコンストラクタの実装に関するヒントを参照してください。

厳格モードで禁止されている機能

厳格モードでは、さらに2つのJavaScript機能が禁止されています。



[8] 単純化のために、宣言は文であると仮定しています。

次:8. 値