簡體   English   中英

Javascript命名的函數定義在不應該執行時執行

[英]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,它可以在一個塊內進行求值。

但整篇文章值得一讀。

另請注意, 在ES5嚴格模式下警告函數語句,並且可能會在ECMAScript的某些未來版本中引入。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM