2012-09-24 56 views
14

這段代碼爲什麼會引發錯誤?(function eval(){})如果函數體在嚴格模式下會引發語法錯誤?

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

現場演示:http://jsfiddle.net/SE3eX/1/

所以,我們在這裏的是一個名爲函數表達式。我想明確指出這個函數表達式出現在非嚴格的代碼中。正如你所看到的,它的功能體是嚴格的代碼。

嚴格的模式規則在這裏:http://ecma-international.org/ecma-262/5.1/#sec-C

相關的子彈是這個(它是名單上的最後一個):

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

只有函數eval()會得到相同的錯誤消息(SyntaxError:函數名稱不能是eval或嚴格模式下的參數) {'嚴格使用'; };' – some

回答

10

§13.1概括應該是什麼的情況下,如你發生:

  • 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.

重點煤礦。您的嚴格模式功能的標識符eval,因此它是SyntaxError。遊戲結束。


明白爲什麼上面是一個「嚴格模式的功能表現,」看語義定義在§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.

重點煤礦。以上顯示了函數表達式(或聲明)如何變得嚴格。它說什麼(用簡單的英語)是一個FunctionExpression有兩種strict情況:

  1. 它從use strict上下文調用。
  2. 其功能主體以use strict開頭。

你的困惑從思想出現,只有函數體strict,而事實上,整個函數表達式strict。你的邏輯雖然直觀,但並不是JS的工作方式。


如果您想知道爲什麼ECMAscript以這種方式工作,這很簡單。假設我們有這樣的:

// 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 
})(); 

值得慶幸的是,上面的代碼將拋出,因爲整個函數表達式被標記爲strict

+1

釘了它。這正是這裏發生的事情 – Claudiu

+0

因此,一個函數表達式出現在非嚴格代碼中,但其函數體是嚴格代碼,是一種「嚴格模式函數表達式」?你能在標準中找到這個定義嗎? –

+1

@ŠimeVidashttp://ecma-international.org/ecma-262/5.1/#sec-10.1.1 - 「屬於FunctionDeclaration,FunctionExpression或訪問器PropertyAssignment **的函數代碼是嚴格的函數代碼** if其FunctionDeclaration,** FunctionExpression **或PropertyAssignment包含在嚴格模式代碼或**中,如果功能代碼以包含使用嚴格指令**的指令序言開頭。 – Pete

1

我猜測它會拋出一個錯誤,因爲函數eval內部會指向現在違反嚴格模式的函數本身。

3

偉大的問題!

因此,要找到答案你的問題,你真的需要看看process for declaring a function(具體而言,步驟3-5 - 強調):

  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.

那麼,什麼情況是,你的EVAL使用在步驟3中創建綁定時不是問題,但是一旦它遇到步驟5,它就試圖在嚴格的詞彙環境(即分配給eval)中初始化eval的綁定,這是不允許的,因爲我們是在嚴格的情況下,遵循第4步。

請記住,限制不是初始化一個新的eval變量。它使用Assignment操作符的LeftHandSideExpression,這是函數聲明過程的第5步中發生的情況。

UPDATE:

正如@DavidTitarenco指出的,這是明確部13.1覆蓋(除了隱含限制在部分13)。

+0

嗯,我不認爲'InitializeImmutableBinding'使用賦值運算符。源代碼中賦值運算符「存在」,而「InitializeImmutableBinding」是內部方法。我懷疑它是在* JavaScript中定義的。 –

+0

@ŠimeVidas你是對的。它似乎沒有違反規範的字母,但它似乎違反了規範的*精神*。這是你必須在ECMAScript的常規基礎上考慮的問題。 : - /(這是代碼,「你的猜測和我一樣好」 - 我希望我能兩次提出這個問題)。 – Pete

相關問題