2014-05-07 33 views
0

我對這個主題感到困惑,這對於我來說非常重要,就異步函數調用和閉包而言。我一定錯過了javascript函數調用中最重要的部分,到目前爲止還無法找到我的問題的答案,因此我希望對您有所幫助!爲異步內部函數執行外部函數更改的函數參數嗎?

我的問題假定:

  1. 外功能fDynamic調用與一些參數i(= O)
  2. fDynamic隊列內功能fInnerQueued,要在某個時間點的未來調用。
  3. 在外部函數fDynamic與不同的參數i再次調用的平均時間(= 1)

一旦這是新的參數值現在到第一內功能fInnerQueued這將看到的變化可見,因爲它終於被調用? ...似乎不是?

看來,如果函數的參數是不是免費的變量,並緊密結合的函數調用範圍甚至低谷異步調用。

這裏有一個fiddle,這裏的本質:

var j = 0; 
var fDynamic = function(i) { 
    j = i; // j seems to be a free variable, while i is not? 
    if(i == 0) { 
    // Delay execution in order to let i change to 1 
    var fInnerQueued = function() { 
     console.log(i + ' ('+ j + ')'); //should be "1 (1)" but is "0 (1)" 
    } 
    setTimeout(fInnerQueued, 100); 
    } else { 
    console.log(i); // is "1 (1)", right! 
    } 
}; // Expected output "1 (1)", "1 (1)" but it is "1 (1)", "0 (1)"... 
fDynamic(0); 
fDynamic(1); 

我測試了它也node.js的,並得到了相同的,有些出人意料,輸出。

我通過不同的崗位抓取和沒能找到答案:

我知道我可以通過創建屏蔽閉合或使用綁定來省略麻煩。但我真的很想理解爲什麼函數參數不被視爲內部函數的自由變量,並且它們甚至通過異步調用來保留。

回答

1

函數的參數是局部範圍的變量。

function foo (x) { 

} 
foo(1); 

是大致相同

function foo() { 
    var x = 1; 
} 
foo(); 

function foo() { 
    x = 1; 
} 
foo(); 

當您使用的內部函數的參數被關閉了。

調用函數再創一個新的作用域的新變量。

+0

因此每個調用都會創建一個新的範圍?我認爲函數就像通過不同調用共享相同範圍的實例。這是我不需要考慮的時候只使用同步的東西。 – Dominic

+1

是的。每個函數調用都會創建自己的範圍。 – Quentin

0

這很簡單:i是一個函數上下文變量,當解析器完成解析它被刪除的函數時。 j是全局上下文中的變量,因此它在函數退出時不會被刪除。

當您兩次調用該函數時,會爲每個調用創建一個新的上下文,並且i在此處,因爲i不是類變量而是參數。第一次調用它時,會保留「舊」上下文,以便您的子函數可以在子上下文中執行,其中i仍然爲0.發生這種情況時,第二次調用的i已經消失,只有j全局上下文被保留。

+0

所以你告訴我解析器每次調用時都會在函數上運行?這很有趣。因爲我有點認爲它會通過在全局上下文中定義函數來減少解析器的工作量。如果他在調用之前解析它們,我可以按照我認爲合適的方式將它們拉近距離。 – Dominic

+0

是的,我猜這很簡單,如果你知道引擎是如何工作的;)我希望這是一個簡單而邏輯的答案。到目前爲止找不到答案。 – Dominic

+0

它實際上並不解析,它會創建一個上下文。上下文是某種包含所有當前變量的「列表」,並將它們分開。沒有它,函數a中的參數'i'會在函數b中與您的迭代變量'i'發生衝突。範圍意味着所有當前受影響的情況。 – Sebb

0

沒有區別是否調用函數同步或異步的方式(例如,通過setTimeout的)作爲昆汀正確地指出

函數的參數是局部範圍的變量。

請參閱the updated fiddle(fStatic被稱爲2次奇偶與fDynamic)

appendLog("Static Argument, changed within function (expected: 0, 1, 0, 1):"); 
var fStatic = function(i) { 
var fPrintArg = function() { 
appendLog(i); 
}; 
setTimeout(fPrintArg, 100); 
fPrintArg(); 
}; 
fStatic(0); 
fStatic(1); 

的結果是相同的:ⅰVAR的作用域確定爲每個外的函數調用。

相關問題