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

use*_*782 1 javascript variables lifetime

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

var add = (function () {
        var counter = 0;
        return function () {return counter += 1;}
    })();
    add();
    add();
    add();
Run Code Online (Sandbox Code Playgroud)

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

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

T.J*_*der 7

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

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

counter在IIFE返回后,您的变量继续存在,因为它创建的函数和returns(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);
}
Run Code Online (Sandbox Code Playgroud)

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