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
确切来说,不是。虽然在《JavaScript高级程序设计》中作者描述,闭包是指有权访问另一个函数作用域中的变量的函数,《JavaScript权威指南》中也有关于闭包的解释,从技术的角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链。不可否认,在 JavaScript 中,如果你在另一个函数中使用了 function 关键字(eval也会创建闭包),就创建了一个闭包,但是闭包不只是函数,还应该包括函数可访问的词法作用域。
JavaScript
语言中一个非常重要但又难以掌握,近乎神话的概念:闭包
。垃圾回收机制
解释什么是闭包之前,有必要简单了解下垃圾回收的机制。
JavaScript
中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收,如果两个对象相互引用,而没有被第三者引用,那么这两个相互引用的对象也会被垃圾回收机制回收。垃圾回收的实现方式有
引用计数
和标记清除
,引用计数无法解决循环引用的问题,现代浏览器的垃圾回收机制实现要复杂的多,本文的主角不是垃圾回收机制,贴一个V8
的 传送门,有兴趣的读者可以深入了解。什么是闭包
闭包是函数和声明该函数的词法环境的组合。简单来说,当函数可以记住并访问其所在的词法作用域时(即使函数是在当前词法作用域外执行),就产生了闭包。其实通过枯燥的定义和术语来理解闭包是不推荐的,最好的方式还是结合代码:
确切来说,不是。虽然在
《JavaScript高级程序设计》
中作者描述,闭包是指有权访问另一个函数作用域中的变量的函数
,《JavaScript权威指南》
中也有关于闭包的解释,从技术的角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链
。不可否认,在JavaScript
中,如果你在另一个函数中使用了function
关键字(eval也会创建闭包
),就创建了一个闭包,但是闭包不只是函数,还应该包括函数可访问的词法作用域。在早期的
MDN
版本中,认为闭包是引用了自由变量的函数,让很多人误认为自由变量是存储在堆内存中,现在看来这种说法并不准确。JavaScript
中数据到底是存储在堆
还是栈
中,跟数据的类型有关。栈
中一般存放一些简单数据段,对应到JavaScript
的数据类型,就是基本数据类型:String, Boolean, Number, Symbol, Undefined, Null
,栈
中存储的是基本数据类型的值,访问的方式是按值访问。引用类型的值存放在
堆
中,也就是堆内存
中的对象,如果一个变量的类型是引用类型,那么变量中保存的实质上是一个指针,也就是一个内存地址,这个内存地址存放在栈
中,访问的方式是,首先从栈
中读取内存地址,然后沿着指针找到堆
中对应的对象。我们知道,闭包包含了函数及其可访问的词法环境,这里的词法环境实质上是一条作用域链,作用域链上可能有基本类型的变量,也有引用类型的变量,所以确切的说,闭包存储在堆栈中而非堆中。
闭包的缺陷
闭包的缺陷主要有两种:
占用内存
和可能造成内存泄漏
。占用内存很好理解,因为闭包创建时携带了可访问的词法环境,为什么说闭包可能造成内存呢?
这个主要是针对老版本的 IE 而言。我们知道,内存泄漏最常见的原因就是因为循环引用,在 IE 早期的垃圾回收处理机制中,使用的是引用计数的方式,在 IE8 及其以下的浏览器中的 DOM 和 BOM 对象中创建闭包(比如绑定事件回调),如果不清除循环引用手动释放,就会造成内存泄漏。
闭包的应用
(完)
The text was updated successfully, but these errors were encountered: