关于Javascript闭包的理解

Posted simple-yu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Javascript闭包的理解相关的知识,希望对你有一定的参考价值。

以下内容属个人理解,如有看不明白或漏洞之处,纯属水平不佳,还望见谅。

 

关于闭包,高程里的定义是:指有权访问另一个函数作用域中的变量的函数。创建闭包最常见的方法就是在一个函数的内部再创建一个函数。

这里先创建一个函数f

function f(v1, v2) {

// 函数表达式

}

并进行调用

let result = f(5, 10)

为了搞懂闭包,首先要明白上面程序整个过程中发生了什么:

1.当调用f()函数的时候,后台创建了一个f()的执行环境与相应的作用域链(这里的作用域链的来源:在创建f()函数的时候,会创建一个预先包含了全局变量对象的作用域链,并

保存在内部的[[Scope]]属性中,当调用f()函数时,会先创建执行环境,然后通过复制[[Scope]]中的作用域链来构建自己的作用域链

2.使用arguments和其他被命名的参数的值来初始化f()的活动对象(这里的活动对象将会被推入作用域的前端,全局变量对象始终位于最后一位,外部函数的活动对象始终位于第二位,外部函数的外部函数的活动对象始终位于第三位...以此类推,在f()函数的作用域链中包含两个变量对象:本地活动对象和全局变量对象(这里还要注意,全局变量对象是始终存在的,而本地活动对象只有在函数调用的时候才存在,同时作用域链中,仅仅是对对象的引用,而非真的包含这些对象)

3.函数调用结束后,执行环境和作用域链被销毁。

明白过程中后,我们再来看何谓闭包

这里创建一个函数f1,并在其内部返回一个匿名函数

function f1 (v1) {

  return functiono (v2, v3) {

    let o1 = v2 * v1

    let o2 = v3 * v1

    return o1 + o2

  }

}

let sum = f1(5)

let result = sum(2, 3)

sum = null // 解除对匿名函数的引用,释放内存

在上述代码执行后,产生的执行环境和作用域链的关系如下图所示

技术图片

(这里因为手残画图太丑,就用高程里的这张图代替...将createComparisonFunction当作f1就可以,其余变量自行脑部替换)

在 let sum = f1(5)这里,匿名函数从f1中被返回,其作用域链中包含了本地活动对象,f1的活动对象以及全局变量对象,在f1执行完毕后,执行环境被销毁,但其活动对象却不会被销毁,因为在f1返回的匿名函数的作用域链中,依旧保持着对f1活动对象的引用,只有当匿名函数也销毁了以后,才能真正的销毁所有的活动对象。

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多,我们建议读者只在绝对必要时再考虑使用闭包。虽然像V8 等优化后的JavaScript 引擎会尝试回收被闭包占用的内存,但请大家还是要慎重使用闭包。

以上是关于关于Javascript闭包的理解的主要内容,如果未能解决你的问题,请参考以下文章

[译] 我从没理解过 JavaScript 闭包

关于javascript闭包理解

Javascript关于闭包的个人理解

关于Javascript闭包的理解

关于Javascript闭包(Closure)

关于javascript面向对象之闭包