2012-09-24 8 views
14

なぜこのコードはエラーを送出しますか?(関数eval(){})は、関数本体がstrictモードの場合に構文エラーをスローしますか?

// global non-strict code 
(function eval() { 'use strict'; }); 

ライブデモ:http://jsfiddle.net/SE3eX/1/

だから、私たちがここに持っていることという名前の関数式です。この関数の式が非厳密なコードであることを明示的に指摘したいと思います。ご覧のように、関数本体は厳密なコードです。

strictモードのルールはここにある:http://ecma-international.org/ecma-262/5.1/#sec-C

関連弾丸はこの1つ(それはリストの最後の一つです)です:このルールにのみ適用方法

It is a SyntaxError to use within strict mode code the identifiers eval or arguments as the Identifier of a FunctionDeclaration or FunctionExpression or as a formal parameter name (13.1). Attempting to dynamically define such a strict mode function using the Function constructor (15.3.2) will throw a SyntaxError exception.

気付いた場合は、関数宣言/式自体は厳密なコードで表示されますが、上記の例ではではなくです。

でも、それでもエラーは発生しますか?どうして?

+3

ここではまったく推測していますが、*式*では、名前を持つ関数のインスタンス化式はその関数内でのみ*その名前をバインドするという事実と関係しているかもしれません。言い換えれば、内部的には、関数への参照で初期化されたローカル変数を作成する 'var'宣言のためのいくつかの魔法のようなものです。したがって、グローバルシンボル "eval"をローカルにバインドしようとしているかのようです。 – Pointy

+0

@Pointy良いヒント。そのシナリオで何が起こっているのかを確かめるために標準をチェックしなければならないでしょう... –

+1

'function eval()だけのエラーメッセージ(SyntaxError:関数名は厳密なモードではevalや引数ではないかもしれません) {'厳密な使用'; }; ' – some

答えて

10

§13.1は、何がそのようなあなたのような場合に起こるべき概説します。厳密モードの関数の識別子がの場合、evalとなるので、SyntaxErrorです。ゲームオーバー。


上記 "strictモードの関数式、" §13(関数定義)におけるセマンティック定義を見ている理由は:

The production
FunctionExpression : functionIdentifieropt(FormalParameterListopt) {FunctionBody} is evaluated as follows:

  1. Return the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in the LexicalEnvironment of the running execution context as the Scope. Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.

重点鉱山。上記は、関数式(宣言)がどのように厳密になるかを示しています。これは、use strictコンテキストから呼ばれています

  1. :何それは(平易な英語で)言うことはFunctionExpressionstrict 2でのシナリオであるということです。
  2. 機能の本体はuse strictで始まります。

あなたの混乱は唯一関数本体は、実際には、全体関数式strictあるとき、strictであることを考えるから生じます。ロジックは直感的ですが、JSの仕組みではありません。


なぜECMAscriptがこのように動作するのか不思議であれば、それはかなり簡単です。我々はこれを持っていると仮定します。全体関数式strictとしてフラグ付けされているため

// look ma, I'm not strict 
(function eval() { 
    "use strict"; 
    // evil stuff 
    eval(); // this is a perfectly legal recursive call, and oh look... 
      // ... I implicitly redefined eval() in a strict block 
    // evil stuff 
})(); 

ありがたいことに、上記のコードがスローされます。

+1

と釘付けになった。これはまさにここで起こっていることです – Claudiu

+0

非厳密なコードではあるが、関数本体が厳密なコードである関数式は "strict mode function expression"ですか?この定義を標準で見つけることができますか? –

+1

@ imeVidas http://ecma-international.org/ecma-262/5.1/#sec-10.1.1 - "FunctionDeclaration、FunctionExpression、またはアクセサPropertyAssignment **の一部である機能コードは、厳密な関数コードです** ifそのFunctionDeclaration、** FunctionExpression **、またはPropertyAssignmentは厳密なモードのコードに含まれているか、**機能コードがUse Strict指令**を含む指令Prologueで始まる場合**です。 – Pete

1

私は関数evalの中で厳密なモードに違反している関数自体を指しているので、エラーをスローすると思います。

  • It is a SyntaxError if any Identifier value occurs more than once within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression.
  • It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs within a - FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression.
  • It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the Identifier of a strict mode FunctionDeclaration or FunctionExpression.

強調鉱山:

3

大きな質問です!

ですから、実際に(具体的には、3-5ステップ - 強調は追加)process for declaring a functionを見てする必要がありますあなたの問題への答えを見つけるために:何が起こることはevalの使用ということで、だから、

  1. ...
  2. ...
  3. Call the CreateImmutableBinding concrete method of envRec passing the String value of Identifier as the argument.
  4. Let closure be the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in funcEnv as the Scope.Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.
  5. Call the InitializeImmutableBinding concrete method of envRec passing the String value of Identifier and closure as the arguments.

を手順3でバインディングが作成されても問題はありませんが、手順5に達すると厳密なレキシカル環境内でevalのバインディングを初期化しようとしています(つまり、何かをevalに割り当てています)。ステップ4の後の厳密な文脈の中で。

この制限は新しいeval変数を初期化します。代入演算子のLeftHandSideExpressionとして使用しています。これは、関数宣言プロセスのステップ5で行われます。

UPDATE:@DavidTitarencoが指摘したように

、これは明示的に(セクション13で暗黙の制限に加えて)セクション13.1で覆われています。

+0

うーん、私は 'InitializeImmutableBinding'が代入演算子を利用しているとは思わない。代入演算子はソースコード内に "存在する"一方、 "InitializeImmutableBinding"は内部メソッドである。 JavaScriptで*定義されているかどうかは疑問です。 –

+0

@ imeVidasあなたが正しいです。それは仕様の手紙に違反しているようには見えませんが、スペックの* spirit *に違反しているようです。これはECMAScriptで全般的に定期的に考慮する必要があるものです。 : - /(それは "あなたの推測は私のものと同じくらい良い"というコードです - 私はこの質問を2回upvoteできます)。 – Pete

関連する問題