Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/414.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
javascript中的词法范围、变量生存期和承诺_Javascript_Scope_Promise - Fatal编程技术网

javascript中的词法范围、变量生存期和承诺

javascript中的词法范围、变量生存期和承诺,javascript,scope,promise,Javascript,Scope,Promise,我已经在SO中阅读了大量的答案,但是我无法在脑海中对javascript中的可变生存时间做出清晰的解释。一般来说,答案是关于提升/阴影的,这在我这里不是这样的。例如,我们经常在jQuery中编写这些类型的脚本 function getSomeData() { var $container = $('#someContainer'); $.get('/url', function(data) { $container.html(data); }); } 现在,我的主要问题是,

我已经在SO中阅读了大量的答案,但是我无法在脑海中对javascript中的可变生存时间做出清晰的解释。一般来说,答案是关于提升/阴影的
,这在我这里不是这样的。例如,我们经常在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

让我们把它分解成几个步骤。请注意这里有挥手,包含细节

  • Something调用
    getSomeData
  • 引擎将返回地址推送到堆栈上
  • 引擎为调用创建执行上下文
  • 引擎为上下文创建一个变量环境,用参数、局部变量等填充它
  • 引擎运行函数中的代码
    • 其中一部分是创建回调函数,该函数被赋予对变量环境对象的引用
    • 另一部分是将该函数引用传递给
      $.get
      ,它会保留一段时间
  • 代码执行从函数末尾“脱落”,因此引擎从堆栈中弹出返回地址并继续执行
  • 一段时间后,
    $.get
    通过它保留的对回调的引用调用回调
  • 为回调调用创建一个新的上下文和变量环境
  • 回调代码运行时,会在其自身的变量环境以及创建回调代码的环境中查找内容(对于
    $container
  • 代码执行从函数末尾“脱落”,引擎弹出堆栈,$。get将其对函数的引用丢弃
  • 因为函数没有引用它,所以它符合垃圾收集的条件
  • 在某个时刻,引擎的GC算法会处理该函数,因此该函数不再引用调用
    getSomeData
    的变量环境对象,因此该对象符合GC的条件
  • 在某个时刻,引擎会处理变量环境对象
  • 现在,除了副作用(比如实际使用
    $.get
    中的信息)之外,所有的副作用都被清除了
  • 这种模式会导致性能下降吗

    如果你创建了一个函数并将其保留,那么由于它保留了创建函数时所处的可变环境,这可能会对内存造成影响。但是,一旦您释放了函数(在本例中,一旦
    $.get
    调用了它并删除了对它的引用),就可以对函数进行GC'd,并且可以对变量环境(及其内容)进行GC'd

    在上面我讨论了很多对象和垃圾收集,但是JavaScript引擎当然可以并且可以做一个l