[英]Javascript named function definition executed when it shouldn't
我不知道這里發生了什么。 代碼是:
if( true ) {
console.log('In first function definition');
function test(){
console.log('Hello world');
}
} else {
console.log('In the second function definition');
function test(){
console.log('Goodbye world');
}
}
test();
我希望這會登錄控制台:
'In the first function definition'
'Hello world'
但相反它記錄:
'In the first function definition'
'Goodbye world'
當代碼沒有進入該分支時,如何創建第二個命名函數?
請記住,JavaScript中的所有內容都是功能范圍的; 沒有塊范圍。
為此,您在同一范圍內定義了兩個函數聲明(無論if-else所在的范圍),具有相同的名稱,在不同的塊中。 這會在瀏覽器之間產生不一致的結果
您需要為這些函數指定不同的名稱,或使用函數表達式,如下所示:
var f;
if(true) {
console.log('In first function definition');
f = function(){
console.log('Hello world');
};
} else {
console.log('In the second function definition');
f = function(){
console.log('Goodbye world');
};
}
f();
對你的優秀問題
但是如果我們不輸入代碼的那個分支,那么函數是如何定義的呢? 如果沒有執行該塊,為什么要考慮范圍?
簡單的答案是函數聲明被“提升”,並且即使在聲明本身之前,也可以立即在范圍內的任何位置使用。
即:
function foo(){
f(); //perfectly valid
function f(){
}
}
更長的答案是,在進入范圍之前,所有變量聲明和函數聲明都被刪除,並放在“激活對象”上。 然后將激活對象放置在“范圍鏈”的頭部。 執行該函數時,只需從那里解析對這些變量和函數的任何引用。
javascript中的函數定義獨立於控制結構,這意味着當你第二次重新定義函數時,即使它位於控件結構的一個分支中,它永遠不會點擊它仍然重新定義函數。 無論如何你還想做什么?
一些JavaScript引擎將定義視為始終發生,而不管條件如何,第二個定義將覆蓋第一個定義。
注意:某些JavaScript引擎(不包括SpiderMonkey)錯誤地將任何函數表達式視為函數定義。
要添加到Adam的答案中 ,如果您分配了函數,可以繞過它。
if( true ) {
console.log('In first function definition');
test = function() { console.log('Hello world'); }
} else {
console.log('In the second function definition');
test = function(){ console.log('Goodbye world'); }
}
test();
這將打印
在第一個函數定義中
你好,世界
根據ECMA-262,在執行任何代碼之前處理函數聲明。 因此,在任何地方聲明函數都可以有效地將它們“移動”(“提升”)到執行上下文的頂部。
然而,並非所有看起來像聲明的東西都是聲明。 在下面的:
if (false) {
function fred() {return true;}
}
有些瀏覽器會看到一個函數聲明:
alert(fred());
顯示“真實”。 其他瀏覽器使用ECMA-262的擴展,允許將其視為
命名函數表達式
函數語句(
我將嘗試查找Richard Cornford關於comp.lang.javascript的優秀帖子的引用,
如下所示),以便:
alert(fred());
拋出錯誤, fred未定義。 在Firefox和IE中試用它。
所以底線是如果你想有條件地創建一個函數,使用一個明確的函數表達式。 它們通常與特征測試結合使用,例如,創建一個函數來獲取元素的textContent或innerText:
var getText = (function() {
var el = document.createElement('div');
if (typeof div.textContent == 'string') {
div = null;
return function(el) {return el.textContent;};
} else if (typeof div.innerText == 'string') {
div = null;
return function(el) {return el.innerText;};
}
}());
這是Richard Cornford在FunctionExpression和內存消耗方面的帖子。 重要的部分:
實際上它是一個函數聲明; 一個語法擴展,它能夠允許條件創建一個函數,因為它是一個Statement,它可以在一個塊內進行求值。
但整篇文章值得一讀。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.