我已经阅读了SO中的答案数量,但是我无法在脑海中找到关于javascript中可变生命时间的明确解释。通常答案是约hoisting/shadowing
,这不是imo的情况。例如,我们经常将这些类型的脚本与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);
这种用法有什么优点(除了调试目的和可读性之外)?
如果没有涉及此处的函数调用堆栈,那么在承诺结算之前,$container
存储在哪里?请注意,这种嵌套也是可能的:
function getSomeData() {
var $container = $('#someContainer');
var replaceHtml = function(data) {
$container.html(data);
}
$.get('/url', function(data) {
replaceHtml(data);
});
}
请对此作出明确解释,谢谢!
答案 0 :(得分:2)
现在,我的主要问题是$ container变量如何用于匿名回调函数?
...因此我不得不认为getSomeData实际上仍然保留在函数调用堆栈中,以便为回调函数提供$ container变量,因为据我所知,如果在范围内找不到变量,那么used,interpreter在父范围内查找(到全局范围)。
你真的很接近理解这一点。只需进行一些更正和澄清,您就可以获得。
它与函数调用堆栈无关。在回调运行之前getSomeData
返回你是对的。这意味着它就像正常一样从堆栈中出来。但是,它的局部变量等
生活在,即使该函数已返回。为什么?因为回调有间接引用它们。
调用JavaScript函数时,会创建一个(理论上)对象,该对象是该调用的执行上下文。该上下文包含各种内容,包括一个名为变量环境的对象,其中包含与调用相关的参数和变量。在上下文中创建的任何函数都保持对该上下文的可变环境对象的引用,因此即使该函数已返回,也可以访问它们。这些函数称为闭包,因为它们"关闭"它们的创建环境。
因此,当回调引用$container
变量时,JavaScript引擎查看回调自身的上下文及其变量环境,而不是在那里找到$container
,查看下一个包含环境。它在那里找到$container
并使用它。
让我们把它分解成几步。请注意,此处有挥手示意,the spec包含详细信息。
getSomeData
$.get
,这会让它保持一段时间$.get
通过对其保留$container
)$.get
删除对函数的引用getSomeData
引用变量环境对象,因此该对象符合GC的条件$.get
中的信息),所有内容都已清理这种模式会导致性能下降吗?
不在其中,不是。 如果您创建了一个函数并将其保留在,那么由于它保留了创建它的变量环境,这可能会导致内存影响。但是一旦你释放了这个函数(在这种情况下,一旦$.get
调用它并删除它的引用),那么函数可以是GC,并且变量环境(及其内容)可以是GC' d
在上面我讲了很多对象和垃圾收集,但当然JavaScript引擎可以并且围绕这个做很多优化。它是现代发动机比旧发动机快得多的重要原因。 (只是一部分,但部分。)
如果我将匿名函数更改为声明的函数并使用like;
var callback = function(data) { $container.html(data); } $.get('/url', callback);
这种用法是否有任何优点(除了调试目的和可读性之外)?
没有
如果这里没有涉及函数调用堆栈,那么在容器结算之前,$ container存储在哪里?
见上文。