javascript中的词法范围、变量生存期和承诺
我已经在SO中阅读了大量的答案,但是我无法在脑海中对javascript中的可变生存时间做出清晰的解释。一般来说,答案是关于提升/阴影的javascript中的词法范围、变量生存期和承诺,javascript,scope,promise,Javascript,Scope,Promise,我已经在SO中阅读了大量的答案,但是我无法在脑海中对javascript中的可变生存时间做出清晰的解释。一般来说,答案是关于提升/阴影的,这在我这里不是这样的。例如,我们经常在jQuery中编写这些类型的脚本 function getSomeData() { var $container = $('#someContainer'); $.get('/url', function(data) { $container.html(data); }); } 现在,我的主要问题是,
,这在我这里不是这样的。例如,我们经常在jQuery中编写这些类型的脚本
function getSomeData() {
var $container = $('#someContainer');
$.get('/url', function(data) {
$container.html(data);
});
}
现在,我的主要问题是,$container
变量如何保持对匿名回调函数可用?我知道,当执行达到$.get
时,get
立即返回,getSomeData
最终返回,尽管get
将来可能随时返回。因此,我不得不认为getSomeData
实际上保留在函数调用堆栈中,以便为回调函数提供$container
变量,因为据我所知,如果在所使用的范围内找不到变量,解释器会在父范围(全局范围)中查找它。以下是附带问题:
- 这种模式会导致性能下降吗李>
- 如果我将匿名函数更改为声明函数并使用like
var callback = function(data) {
$container.html(data);
}
$.get('/url', callback);
var callback=函数(数据){
$container.html(数据);
}
$.get('/url',回调)代码>
这种用法有什么好处(除了调试目的和可读性)
- 如果此处没有涉及函数调用堆栈,在承诺解析之前,
$container
存储在哪里?请注意,这种嵌套也是可能的:
函数getSomeData(){
var$container=$(“#someContainer”);
var replaceHtml=函数(数据){
$container.html(数据);
}
$.get('/url',函数(数据){
替换HTML(数据);
});
}
请给出一个明确的解释,谢谢
现在,我的主要问题是$container变量如何可用于匿名回调函数
…因此,我不得不认为getSomeData实际上保留在函数调用堆栈中,以便为回调函数提供$container变量,因为据我所知,如果在所使用的范围中找不到变量,解释器将在父范围(全局范围)中查找它
你很快就明白了。只要几处更正和澄清,你就会明白
它与函数调用堆栈无关。在运行回调之前,getSomeData
返回的消息是正确的。这意味着它会从堆栈中剥离,就像正常情况一样。然而,它的局部变量等等
继续,即使函数已返回。为什么?因为回调具有对它们的间接引用
当调用JavaScript函数时,会创建一个对象(理论上)作为该调用的执行上下文。该上下文包含多种内容,包括一个名为variable environment的对象,该对象包含参数和变量,以及与调用相关的其他内容。在上下文中创建的任何函数都保留对该上下文的变量环境对象的引用,因此即使该函数已返回,也可以访问它们。这些函数称为闭包,因为它们“关闭”了创建它们的上下文
因此,当回调引用$container
变量时,JavaScript引擎会查看回调自己的上下文及其变量环境,而不会在那里找到$container
,而是查看下一个包含环境。它在那里找到并使用$container
让我们把它分解成几个步骤。请注意这里有挥手,包含细节
getSomeData
- 其中一部分是创建回调函数,该函数被赋予对变量环境对象的引用
- 另一部分是将该函数引用传递给
,它会保留一段时间$.get
$.get
通过它保留的对回调的引用调用回调$container
)$。get
将其对函数的引用丢弃getSomeData
的变量环境对象,因此该对象符合GC的条件$.get
中的信息)之外,所有的副作用都被清除了$.get
调用了它并删除了对它的引用),就可以对函数进行GC'd,并且可以对变量环境(及其内容)进行GC'd
在上面我讨论了很多对象和垃圾收集,但是JavaScript引擎当然可以并且可以做一个l