javascript中自调用函数内变量的生命周期是多少

时间:2016-04-25 05:14:47

标签: javascript variables lifetime

我一直在努力理解以下代码:

var add = (function () {
        var counter = 0;
        return function () {return counter += 1;}
    })();
    add();
    add();
    add();

这里为add分配了匿名自我调用函数的返回值 - 即函数function() { return counter += 1 }。现在第一次调用add()时,它会按预期返回1。但第二次调用add()时,它会返回2

我的问题是,因为counter是在函数内部定义的,所以每次函数完成执行时counter都不应该死掉?也就是说,在显示第一次调用add() 1之后。现在我们已经不在那个函数中了,所以不应该counter忘记它以前的值,并且像automatic变量一样从堆栈中销毁?

1 个答案:

答案 0 :(得分:7)

  

javascript中自调用函数内变量的生命周期是什么

与任何其他类型的JavaScript函数中的变量相同:它们只要可以被引用就存在,这有时意味着包含它们的函数返回的时间很长。

在IIFE返回后,您的counter变量继续存在,因为它创建并返回(return function () {return counter += 1;})的函数是变量上的闭包。只要该函数存在,变量就会存在。

更专业地说:调用一个函数为该调用创建一个名为执行上下文的东西,它有一个变量环境对象。在调用期间创建的任何函数都会接收对该外部变量环境对象的引用;与所有对象一样,该对象只要存在对它的引用就存在,因此这些函数使对象保持活动状态。变量实际上是变量环境对象的属性,因此只要某些东西引用了它们所依赖的对象,它们就会存在。 (这是非常简化的形式。)虽然理论上保留了整个变量环境对象,但实际上如果优化效果不可观察,JavaScript引擎可以自由优化,因此实际上并非实际的变量闭包使用可能(或可能不会)释放,具体取决于引擎和函数中的代码。

你的IIFE只能被调用一次,因此只能有一个counter,但创建一个闭包被多次调用的函数很常见,在这种情况下你有多个变量对象,以及关闭的变量的多个副本。

示例:



function helloBuilder(name) {
  var counter = 0;
  return function() {
    ++counter;
    display("Hi there, " + name + ", this is greeting #" + counter);
  };
}

var helloFred = helloBuilder("Fred");
var helloMaria = helloBuilder("Maria");


helloFred();  // "Hi there, Fred, this is greeting #1"
helloFred();  // "Hi there, Fred, this is greeting #2"
helloMaria(); // "Hi there, Maria, this is greeting #1"
helloMaria(); // "Hi there, Maria, this is greeting #2"
helloFred();  // "Hi there, Fred, this is greeting #3"

function display(msg) {
  var p = document.createElement('p');
  p.appendChild(document.createTextNode(msg));
  document.body.appendChild(p);
}




在上文中,helloBuilder 返回的函数将关闭name参数及其counter变量。 (因为参数也存储在执行上下文的变量对象中。)因此我们可以看到,在调用它两次后,有两个变量对象,每个变量对象都有自己的namecounter,我们要求helloBuilder创建的每个函数引用的一个。