JavaScript闭包-函数作用域

JavaScript闭包-函数作用域,javascript,browser,memory-leaks,scope,closures,Javascript,Browser,Memory Leaks,Scope,Closures,我有一个关于JavaScript闭包的问题,特别是在调用(内部)函数时的范围。 这个问题还与浏览器内存泄漏有关,我们将看到 首先对我的问题做一个“简短”的介绍: 因此,我知道当调用函数时,它会进入执行上下文(添加在调用堆栈顶部)。创建一个“激活对象”,其中包含所有局部变量、函数的arguments对象和添加到其中的参数(作为属性) 由于内部函数可以访问封闭函数的变量——即使内部函数在其封闭函数的执行结束后被调用——因此必须对“free”(=外部)变量进行一些引用。这由范围链管理,范围链也添加到执

我有一个关于JavaScript闭包的问题,特别是在调用(内部)函数时的范围。
这个问题还与浏览器内存泄漏有关,我们将看到

首先对我的问题做一个“简短”的介绍:

因此,我知道当调用函数时,它会进入执行上下文(添加在调用堆栈顶部)。创建一个“激活对象”,其中包含所有局部变量、函数的arguments对象和添加到其中的参数(作为属性)

由于内部函数可以访问封闭函数的变量——即使内部函数在其封闭函数的执行结束后被调用——因此必须对“free”(=外部)变量进行一些引用。这由范围链管理,范围链也添加到执行上下文中

根据,执行上下文的作用域由列表顶部的实际激活对象组成,该列表隐藏保存在函数本身上:

范围由对象列表(或链)组成。每个函数对象都有一个内部[[scope]]属性[…]分配给函数调用的执行上下文的范围由相应函数对象的[[scope]]属性所引用的列表组成,激活对象添加在链的前面(或列表的顶部)

这是完全合乎逻辑的,因为由于这个内部作用域属性,存在对自由变量的引用,因此首先闭包能够到达变量(通过作用域链),其次它防止垃圾收集器在封闭函数的执行结束时释放相关的内存

简言之:作用域链(包括函数的内部作用域属性)是闭包如此工作的原因


现在具体地回答我的问题:

哪些变量被添加到函数的内部作用域属性?

据我所知,以下部分:

闭包是函数和声明该函数的词汇环境的组合。此环境由创建闭包时范围内的任何局部变量组成

。。。这意味着在形成闭包时,对所有局部变量的引用都将添加到内部范围属性中

当闭包没有使用其封闭函数中的所有局部变量时,这似乎有点不必要,但没有关系;真正的问题是,这将导致内存泄漏,我们将在下面看到

考虑以下代码(这是对的一小部分缩减,我们将在后面讨论):

在replace的第一次函数调用之后,将发生以下情况:

  • 优先级=空
  • 对包含以下属性的新对象(比如地址为0x01)的字符串引用:
    • 1MB对象
    • 函数someMethod,其内部scope属性引用了封闭函数的所有局部变量,这意味着也引用了priothing,它为null
在第二次函数调用之后:

  • priothing=对地址为0x01的对象的引用
  • 对包含以下属性的新对象(比如地址为0x02)的字符串引用:
    • 1MB对象
    • 函数someMethod,其内部作用域属性引用了priothing(地址为0x01)
      • priorThing本身指向具有相同结构的对象
发生了什么事

在每次函数调用中,将创建一个新对象,该对象引用之前在函数调用中创建的对象;虽然我们甚至没有在新对象中使用这个对象。这是由于函数闭包的作用域链造成的

所以我们看到保存对封闭函数的所有局部变量的引用是非常糟糕的

一个更好的方法就是保存我们真正需要的东西

因此,从我的结论来看,这确实是这样做的,这将解决我上面描述的内存泄漏问题

但它还说:

但是,一旦任何闭包使用了一个变量,它就会在该范围内所有闭包共享的词汇环境中结束

正如作者在他的例子中所描述的那样,这将产生另一种可能的内存泄漏——但这将是程序员的错误


好的,现在简单总结一下:

  • 是否在闭包的作用域中引用了所有局部变量?()
    • 因为内存泄漏,这将是最糟糕的
  • 如果任何闭包使用变量,所有闭包都引用变量吗?()
    • 这是最好的,因为可以避免内存泄漏——但是如果程序员没有意识到这种行为,可能会发生错误
  • 还是每个闭包都有自己的引用,这取决于它们自己使用的变量?
    • 将完全避免内存泄漏,但需要更多的内存,因为每个闭包都必须有自己的“词汇环境”对象(由内部scope属性引用)
“在闭包的作用域中是否引用了所有局部变量?”-是的,规范是这么说的-因为它本身不涉及垃圾收集。在闭包中使用
eval
时也会发生这种情况,这可能会引用变量。“如果有任何闭包使用它,所有闭包都引用这些变量吗?”-是的,这是一些实现作为优化所做的,但它不会导致错误,因为它是完全透明的。“或者每个闭包都有自己的引用,这取决于它们自己使用的变量?”-不,闭包的作用域是共享的。“都是局部变量吗?”
var theThing = null;
var replaceThing = function () {
  var priorThing = theThing;                // hold on to the prior thing

  theThing = {
    longStr: new Array(1000000).join('*'),  // create a 1MB object
    someMethod: function () {
      console.log("someMessage");
    }
  };
};
setInterval(replaceThing, 1000);            // invoke `replaceThing' once every second