You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
而对于在函数内用 var 关键字声明的局部变量来说,当退出函数时,这些局部变量即失去了它们的价值,它们都会随着函数调用的结束而被销毁。
不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
跟闭包和内存泄露有关系的地方是,使用闭包的同时比较容易形成循环引用,如果闭包的作用域链中保存着一些 DOM 节点,这时候就有可能造成内存泄露。但这本身并非闭包的问题,也并非 JavaScript 的问题。在 IE 浏览器中,由于 BOM 和 DOM 中的对象是使用 C++ 以 COM 对象的方式实现的,而 COM 对象的垃圾收集机制采用的是引用计数策略。在基于引用计数策略的垃圾回收机制中,如果两个对象之间形成了循环引用,那么这两个对象都无法被回收,但循环引用造成的内存泄露在本质上也不是闭包造成的。
相关文章
作用域链
作用域链是一个 对象列表(list of objects),用以检索上下文代码中出现的 标识符(identifiers)。
标示符[Identifiers] 可以理解为变量名称、函数声明和普通参数。
函数
foo
如何访问到变量x
(函数能访问一个更高一层上下文的变量对象)?这种机制是通过函数内部的
[[scope]]
属性来实现的。[[scope]]
是所有父变量对象的层级链,处于当前函数上下文之上,在函数创建时存于其中。[[scope]]
是函数的一个属性,而不是一个上下文环境。[[scope]]
在函数创建时被存储(静态作用域),直至函数销毁。即:函数可以永不调用,但[[scope]]
属性已经写入,并存储在函数对象中。通过构造函数创建的函数的
[[scope]]
通过函构造函数创建的函数的
[[scope]]
属性总是唯一的全局对象。考虑到这一点,如通过这种函数创建除全局之外的最上层的上下文闭包是不可能的。代码执行时对作用域链的影响
在 ECMAScript 中,在代码执行阶段有两个声明能修改作用域链。这就是
with
声明和catch
语句。它们添加到作用域链的 最前端,对象须在这些声明中出现的标识符中查找。with
{ x: 20 }
添加到作用域的最前端;with
内部,遇到了var
声明,当然什么也没创建,因为在进入上下文时,所有变量已被解析添加;x
,实际上对象中的x
现在被解析,并添加到作用域链的最前端,x
为 20,变为 30;y
的修改,被解析后其值也相应的由 10 变为 30;with
声明完成后,它的特定对象从作用域链中移除(已改变的变量x
30 也从那个对象中移除),即作用域链的结构恢复到with
得到加强以前的状态。x
保持同一,y
的值现在等于 30,在with
声明运行中已发生改变。catch
同样,
catch
语句的异常参数变得可以访问,它创建了只有一个属性的新对象:异常参数名作用域链修改为:
Scope = catchObject + AO|VO + [[Scope]]
在
catch
语句完成运行之后,作用域链恢复到以前的状态闭包
ECMAScript 中,闭包指的是:
闭包的作用
1. 私有化变量
2. 延续局部变量的寿命
因为一些低版本浏览器的实现存在 bug,在这些浏览器下使用 report 函数进行数据上报会丢失 30% 左右的数据,也就是说,report 函数并不是每一次 都成功发起了 HTTP 请求。丢失数据的原因是 img 是 report 函数中的局部变量,当 report 函数的调用结束后,img 局部变量随即被销毁,而此时或许还没来得及发出 HTTP 请求,所以此次请求就会丢失掉。
把 img 变量用闭包封闭起来,便能解决请求丢失的问题:
闭包与内存管理
var
关键字声明的局部变量来说,当退出函数时,这些局部变量即失去了它们的价值,它们都会随着函数调用的结束而被销毁。跟闭包和内存泄露有关系的地方是,使用闭包的同时比较容易形成循环引用,如果闭包的作用域链中保存着一些 DOM 节点,这时候就有可能造成内存泄露。但这本身并非闭包的问题,也并非 JavaScript 的问题。在 IE 浏览器中,由于 BOM 和 DOM 中的对象是使用 C++ 以 COM 对象的方式实现的,而 COM 对象的垃圾收集机制采用的是引用计数策略。在基于引用计数策略的垃圾回收机制中,如果两个对象之间形成了循环引用,那么这两个对象都无法被回收,但循环引用造成的内存泄露在本质上也不是闭包造成的。
如果要解决循环引用带来的内存泄露问题,我们只需要把循环引用中的变量设为
null
即可。将变量设置为null
意味着切断变量与它此前引用的值之间的连接。参考
The text was updated successfully, but these errors were encountered: