標準參考

函式宣告和函式表示式

定義一個函式有兩種途徑:函式宣告和函式表示式。

函式宣告:
function Identifier ( FormalParameterList

opt

 ) { FunctionBody }
函式表示式:
function Identifier

opt

 ( FormalParameterList

opt

 ) { FunctionBody }

ECMAScript 根據上下文來區分函式宣告和函式表示式,假設 "function test(){}" 是一個表示式的一部分,它就是一個函式表示式,否則它就是一個函式宣告。

關於函式宣告和函式表示式的更多資訊,請參考 ECMAScript 規範 13 Function Definition 中的內容。

函式宣告可以出現的位置

根據 ECMAScript 規範第 13 章 Function Definition 和第 14 章 Program 中的描述,函式宣告只能出現在 Program(程式,即全域性環境)或函式體內。

換句話說,函式宣告不能出現在( 如 if、while 或 for 語句)中。

問題描述

Firefox 的 TraceMonkey 引擎對函式宣告的處理與 ECMAScript 規範的要求不符,TraceMonkey 將塊中的函式宣告作為“函式語句”來處理。而其他瀏覽器的引擎仍將這類塊中的函式聲明當作該塊之外的函式宣告來解析。

造成的影響

對塊語句中的函式宣告的處理差異,將導致某些功能不能按照預期實現,甚至程式碼出錯。

受影響的瀏覽器

Firefox  

問題分析

TraceMonkey 將塊中的函式宣告作為“函式語句”來處理。而其他瀏覽器的引擎仍將這類塊中的函式聲明當作該塊之外的函式宣告來解析。

分析以下程式碼:

function foo(){
if(window===parent){
function bar(){alert(1);}
}
else{
function bar(){alert(2);}
}
bar();
}
foo();

以上程式碼中,兩個識別符號相同的函式宣告被放在了 if...else... 塊中。這不符合規範的約定,但各引擎的處理辦法並不相同。

TraceMonkey 將這種位於塊內的函式宣告解析為“函式語句”,因此僅能被執行到的那個“函式語句”會生效,而其他瀏覽器則將二者仍看作當前作用域的函式宣告,即不論 if...else... 的哪個分支最終會被執行,後者始終會覆蓋前者,作為函式體 foo 內的、識別符號為 foo 的函式存在。

注:Firefox 中在 if...else... 中使用函式宣告的解析方式,在 MDC 中也有描述,參見:Conditionally defining a function

假設以上程式碼的判斷條件 window===parent 為 true,各瀏覽器下的輸出結果,如下表所示:

Firefox 其他瀏覽器
1 2

ECMAScript 規範第 5 版 12 章中的 Note 部分提到,雖然有些實現可以將函式宣告作為語句處理,但這是不提倡的。

注:本文部分內容參考了文章:命名函式表示式探祕 中的內容。

解決方案

將條件語句中的函式宣告替換為函式表示式,如:

function foo(){
if(window===parent){
var bar=function(){alert(1);}
}
else{
var bar=function(){alert(2);}
}
bar();
}
foo();

參見

知識庫

相關問題

測試環境

作業系統版本: Windows 7 Ultimate build 7600
瀏覽器版本: IE6
IE7
IE8
Firefox 3.6
Chrome 4.0.302.3 dev
Safari 4.0.4
Opera 10.51
測試頁面: ...
本文更新時間: 2010-07-09

關鍵字

函式宣告 函式表示式 語句塊 同名函式 Conditionally defining a function

轉載

http://w3help.org/zh-cn/causes/SJ9002