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
functioncoolModule(){letname="Mike"letage=20functionsayName(){console.log(name)}functionsayAge(){console.log(age)}return{
sayName,
sayAge,}}letinfo=coolModule()info.sayName()// ==> Mike
闭包的定义
闭包是指有权访问另一个函数作用域中的变量的函数,但是闭包不只是函数,还应该包括函数可访问的词法作用域(因为作用域链)。
闭包有三个作用域范围:
创建函数的父级上下文的数据是保存在函数的内部属性 [[Scope]] 中的。如果对 [[Scope]] 和作用域链的知识完全理解了的话,那对闭包也就完全理解了。
根据函数创建的算法,我们看到 在 ECMAScript 中,所有的函数都是闭包,因为它们都是在创建的时候就保存了上层上下文的作用域链(除开异常的情况) (不管这个函数后续是否会激活 —— [[Scope]] 在函数创建的时候就有了)。
所有对象都引用一个[[Scope]]:
这里还要注意的是:在 ECMAScript 中,同一个父上下文中创建的闭包是共用一个 [[Scope]] 属性的。也就是说,某个闭包对其中 [[Scope]] 的变量做修改会影响到其他闭包对其变量的读取。
这就是说:所有的内部函数都共享同一个父作用域。
这里只有一类函数除外,那就是通过 Function 构造器创建的函数,因为其[[Scope]]只包含全局对象。
为了更好的澄清该问题,我们对 ECMAScript 中的闭包给出2个正确的版本定义:
ECMAScript中,闭包指的是:
闭包是如何产生的
以下过程引用自极客时间的《浏览器工作原理与实践》的第12章
先看以下代码:
当 foo 函数的执行上下文销毁时,由于 foo 函数产生了闭包,所以变量 myName 和 test1 并没有被销毁,而是保存在内存中,那么应该如何解释这个现象呢?
要解释这个现象,我们就得站在内存模型的角度来分析这段代码的执行流程:
通过上面的分析,我们可以画出执行到 foo 函数中“return innerBar”语句时的调用栈状态,如下图所示:
从上图你可以清晰地看出,当执行到 foo 函数时,闭包就产生了;当 foo 函数执行结束之后,返回的 getName 和 setName 方法都引用“clourse(foo)”对象,所以即使 foo 函数退出了,“clourse(foo)”依然被其内部的 getName 和 setName 方法引用。所以在下次调用bar.setName或者bar.getName时,创建的执行上下文中就包含了“clourse(foo)”。
总的来说,产生闭包的核心有两步:第一步是需要预扫描内部函数;第二步是把内部函数引用的外部变量保存到堆中。
闭包的作用
能够访问函数定义时所在的词法作用域(阻止其被回收)。
私有化变量
模块模式具有两个必备的条件(来自《你不知道的JavaScript》):
参考文章
The text was updated successfully, but these errors were encountered: