web-dev-qa-db-ja.com

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

まあ、最初に私はおそらくこれがブラウザに依存しているかどうか尋ねるべきです。

無効なトークンが見つかったが、その無効なトークンまでコードのセクションが有効である場合、改行が先行する場合はトークンの前にセミコロンが挿入されます。

ただし、セミコロンの挿入によって引き起こされるバグの一般的な例は次のとおりです。

return
  _a+b;

_aは有効なトークンであるため、この規則には従っていないようです。

これに対して、コールチェーンの分割は期待通りに動作します。

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

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

360
T.R.

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

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

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

3つのケースが説明されています。

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

    • トークンは前のトークンと少なくとも1つのLineTerminatorで区切られています。
    • トークンは}です

    例:

    { 1
    2 } 3
    

    に変換されます

    { 1
    ;2 ;} 3;
    

    NumericLiteral1が最初の条件を満たしています。次のトークンは行末記号です。
    2が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";
    
392
CMS

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

7.9.1セミコロンの自動挿入規則

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

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

ただし、前述の規則には追加のオーバーライド条件があります。セミコロンが空のステートメントとして解析される場合、またはそのセミコロンがヘッダーの2つのセミコロンのうちの1つになる場合、セミコロンは自動的に挿入されません。 for ステートメント(12.6.3を参照).

40
Jörg W Mittag

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

見積もり:

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

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

var a
a
=
3 console.log(a)

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

そして:

1行目のステートメントの継続として2行目を解析できない場合、JavaScriptは改行をセミコロンとして解釈するという一般規則の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
}

それが適切に動作するために。また、ステートメントの後に;を使用する規則に従う場合は、自分で;を挿入できます。

return { 
  foo: 1
};
34

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

    var srcRecords = src.records
        srcIds = [];

実行されましたが、その効果はsrcIds宣言/代入が大域的だったことです。前の行のvarを使ったローカル宣言は、セミコロンの自動挿入により終了したと見なされたため適用されなくなったためです。

17
George Jempty

JavaScriptの 自動セミコロン挿入 の最も文脈的な説明は、 Crafting Interpreters に関する本に由来しています。

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

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

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

1
jchook