2014-05-07 31 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的作用域确定为每个外的函数调用。

相关问题