JavaScriptの自動セミコロン挿入(ASI)のルールは何ですか?


445

さて、まず、これがブラウザに依存しているかどうかを尋ねるべきでしょう。

無効なトークンが見つかった場合、コードのセクションはその無効なトークンまで有効で、改行が前に付いている場合、トークンの前にセミコロンが挿入されることを読みました。

ただし、セミコロンの挿入が原因で発生するバグの一般的な例は次のとおりです。

return
  _a+b;

..これは、_aが有効なトークンになるため、このルールに従っていないようです。

一方、コールチェーンの分割は期待どおりに機能します。

$('#myButton')
  .click(function(){alert("Hello!")});

誰かがルールのより詳細な説明を持っていますか?


22
そこの仕様は ...
マイル

33
@Milesリンク切れではありません;-) ecma-international.org/publications/standards/Ecma-262.htm
Zach Lysobey

3
を参照してください。上記の26のPDF。
'2015


セクション11.9「セミコロンの自動挿入」を参照
Andrew Lam

回答:


454

まず、自動セミコロン挿入(簡潔にするためにASIとも呼ばれます)の影響を受けるステートメントを知っておく必要があります。

  • 空のステートメント
  • var ステートメント
  • 式ステートメント
  • do-while ステートメント
  • continue ステートメント
  • break ステートメント
  • return ステートメント
  • throw ステートメント

ASIの具体的な規則は、仕様§11.9.1に記載されています。自動セミコロン挿入の規則

3つのケースについて説明します。

  1. 文法で許可されていないトークン(LineTerminatorまたは})が検出されると、次の場合にセミコロンがトークンの前に挿入されます。

    • トークンは、少なくとも1つ前のトークンから分離されていますLineTerminator
    • トークンは }

    { 1
    2 } 3

    に変換されます

    { 1
    ;2 ;} 3;

    NumericLiteral 1最初の条件を満たし、次のトークンは、回線終端装置です。第二の条件は、次のトークンを満たしています。
    2}

  2. トークンの入力ストリームの終わりが検出され、パーサーが入力トークンストリームを単一の完全なプログラムとして解析できない場合、セミコロンが入力ストリームの終わりに自動的に挿入されます。

    a = b
    ++c

    に変換されます:

    a = b;
    ++c;
  3. このケースは、文法の生成によってトークンが許可されているが、生成が制限付き生成である場合に発生します。制限付きトークンの前にセミコロンが自動的に挿入されます。

    制限された作品:

    UpdateExpression :
        LeftHandSideExpression [no LineTerminator here] ++
        LeftHandSideExpression [no LineTerminator here] --
    
    ContinueStatement :
        continue ;
        continue [no LineTerminator here] LabelIdentifier ;
    
    BreakStatement :
        break ;
        break [no LineTerminator here] LabelIdentifier ;
    
    ReturnStatement :
        return ;
        return [no LineTerminator here] Expression ;
    
    ThrowStatement :
        throw [no LineTerminator here] Expression ; 
    
    ArrowFunction :
        ArrowParameters [no LineTerminator here] => ConciseBody
    
    YieldExpression :
        yield [no LineTerminator here] * AssignmentExpression
        yield [no LineTerminator here] AssignmentExpression

    の古典的な例ReturnStatement

    return 
      "something";

    に変換されます

    return;
      "something";

4
#1:文法で許可されていないトークンは、通常、行末記号ではありません(#3の制限された生成を意味しない限り)?括弧は省いたほうがいいと思います。#2 ++cわかりやすくするために、例では後の挿入のみを示してはいけませんか?
ベルギ2014

2
ASIが実際に「セミコロンを挿入」する必要はなく、エンジンのパーサーでステートメントを終了するだけであることに注意してください...
Aprillion

1
「入力ストリーム」とは何ですか、それは「ライン」を意味しますか?「入力トークンストリーム」により、理解がやや難しくなっています
非極性2016年

スペックリンクは他の人でも機能しますか?リンク切れのあるほぼ空のページが表示されました。
intcreator 2016

これらのルールに従って、「a [LineBreak] = [LineBreak] 3」の太極者無極而生による以下の例がどのように機能するかを説明してください
Nir O.

45

ECMA-262第5版ECMAScript仕様から直接

7.9.1セミコロンの自動挿入のルール

セミコロン挿入には3つの基本的なルールがあります。

  1. プログラムが左から右に解析されるときに、文法の生成で許可されていないトークン(違反トークンと呼ばれる)が検出された場合、次の1つ以上の場合、違反トークンの前にセミコロンが自動的に挿入されます。条件は真です:
    • 問題のトークンは、少なくとも1つ前のトークンから分離されていますLineTerminator
    • 問題のトークンは}です。
  2. プログラムが左から右に解析されるときに、トークンの入力ストリームの最後が検出され、パーサーが単一の完全なECMAScriptとして入力トークンストリームを解析できないProgram場合、セミコロンが自動的に最後に挿入されます。入力ストリーム。
  3. プログラムが左から右に解析されるときに、文法の生成によって許可されているトークンが検出されたが、生成が制限された生成であり、トークンが注釈の直後の端末または非端末の最初のトークンになる場合" [ LineTerminatorここにはありません] "が制限付きプロダクション内にあり(したがって、そのようなトークンは制限付きトークンと呼ばれます)、制限付きトークンは、少なくとも1つのLineTerminatorによって前のトークンから分離され、セミコロンが制限付きトークンの前に自動的に挿入されます。

ただし、前述のルールには追加の上書き条件があります。セミコロンが空のステートメントとして解析される場合、またはセミコロンがforステートメントのヘッダーの2つのセミコロンの1つになる場合、セミコロンは自動的に挿入されません(12.6を参照)。 .3)。


44

私は仕様のこれら3つのルールをあまり理解できませんでした-よりわかりやすい英語が欲しいのですが-これは私がJavaScriptから収集したものです:The Definitive Guide、6th Edition、David Flanagan、O'Reilly、2011:

見積もり:

JavaScriptはすべての改行をセミコロンとして扱いません。通常、セミコロンなしでコードを解析できない場合のみ、改行をセミコロンとして扱います。

別の引用:コードについて

var a
a
=
3 console.log(a)

JavaScriptは、2番目の改行をセミコロンとして扱いません。これは、長いステートメントa = 3の解析を続行できるためです。

そして:

JavaScriptが2行目を1行目のステートメントの継続として解析できない場合、改行をセミコロンとして解釈するという一般的なルールの2つの例外。最初の例外には、return、break、およびcontinueステートメントが含まれます

...これらの単語の後に改行がある場合... JavaScriptは常にその改行をセミコロンとして解釈します。

... 2番目の例外には++および-演算子が含まれます...これらの演算子のいずれかを後置演算子として使用する場合は、それらが適用される式と同じ行に表示される必要があります。それ以外の場合、改行はセミコロンとして扱われ、++または-は後続のコードに適用される前置演算子として解析されます。たとえば、次のコードを検討してください。

x 
++ 
y

としてx; ++y;ではなくとして解析されますx++; y

だから私はそれを簡略化すると思います、それはつまり:

一般的には、JavaScriptが長く、それが理にかなっているようように、コードの継続として扱います- 2例を除い:のようないくつかのキーワードの後に(1) 、returnbreakcontinueおよび(2)それが見れば++または--新しい行に、それが追加されます;前の行の末尾。

「意味のある限りコードの継続として扱う」という部分は、正規表現の貪欲なマッチングのように感じさせます。

上記のように、つまりreturn改行があると、JavaScriptインタープリターは;

(再度引用:改行がこれらの単語の後に表示された場合(例:return)... JavaScriptは常にその改行をセミコロンとして解釈します)

そしてこの理由により、の古典的な例

return
{ 
  foo: 1
}

JavaScriptインタープリターはそれを次のように扱うため、期待どおりに動作しません。

return;   // returning nothing
{
  foo: 1
}

return:の直後に改行を入れてはいけません。

return { 
  foo: 1
}

それが適切に機能するために。そして、;もしあなたが;after anyステートメントを使うというルールに従うなら、あなた自身を挿入するかもしれません:

return { 
  foo: 1
};

17

セミコロンの挿入とvarステートメントについては、varを使用するが複数行にまたがる場合はコンマを忘れることに注意してください。誰かが昨日私のコードでこれを見つけました:

    var srcRecords = src.records
        srcIds = [];

実行されましたが、効果はsrcIds宣言/割り当てがグローバルであったことです。自動セミコロンの挿入によりステートメントが完了したと見なされ、前の行にvarを指定したローカル宣言が適用されなくなったためです。


4
これがちょっと私がjsLintを使う理由です
Zach Lysobey

1
コードエディタでJsHint / Lintを実行してすぐに応答:)
dmi3y

5
@balupton行末のコンマを忘れるとセミコロンが自動挿入されます。ルールとは対照的に、それは「雑談」のようなものでした。
Dexygen、2014

1
baluptonは正しいと思います。次のように書くと違いがありますvar srcRecords = src.records srcIds = [];。1行でカンマを忘れるか、「return a && b」と書いて何も忘れないでください。これはASIルールで定義されています...
セバスチャン

3
各行にタイプするvarletconst)の明快さは、タイプするのにかかる秒の端数を上回ると思います。
squidbe

5

私が見つけたJavaScriptの自動セミコロン挿入の最も文脈的な説明は、Crafting Interpretersに関する本から来ています。

JavaScriptの「セミコロンの自動挿入」ルールは奇妙なものです。他の言語がほとんどの改行は意味があり、複数行のステートメントで無視する必要があるのはほんのわずかであると想定する場合、JSはその逆を想定します。解析エラーが発生しない限り、改行はすべて無意味な空白として扱われます。含まれている場合は、戻って前の改行をセミコロンに変えて、文法的に有効なものを取得します。

彼はあなたが匂いコードするようにそれを説明し続けます。

このデザインノートは、それがどのように機能するかについて完全に詳細に説明した場合、デザインダイアトリに変わりますが、それが悪いアイデアであるさまざまな方法のすべてではありません。それは混乱です。JavaScriptは私が知っている唯一の言語で、多くのスタイルガイドでは理論的には省略できるにもかかわらず、すべてのステートメントの後に明示的なセミコロンが必要です。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.