资讯专栏INFORMATION COLUMN

学习笔记:JavaScript 闭包是怎么通过作用域链霸占更多内存的?

HmyBmny / 2779人阅读

摘要:闭包是怎么通过作用域链霸占更多内存的本文是作者学习高级程序设计第一小节的一点个人理解,详细教程请参考原教材。函数执行过程创建了一个函数的活动对象,作用域链的最前端指向这个对象。函数执行完毕返回值后执行环境作用域链和活动对象一并销毁。

JavaScript 闭包是怎么通过作用域链霸占更多内存的?

本文是作者学习《JavaScript 高级程序设计》7.2第一小节的一点个人理解,详细教程请参考原教材。

在弄清楚这个问题之前,我们有必要搞清楚下面这几个问题:

首先,什么是闭包?

定义:闭包 是指 有权访问另一个函数作用域中变量的函数。

怎么创建闭包?

在一个函数内部创建另一个函数,是创建闭包最常见的方式。

一个一般的函数执行的时候都发生了什么?

创建一个执行环境,里面有这个函数的变量对象,保存了函数可访问的所有数据。

创建了作用域链,用来保证可访问变量的有序访问。

函数执行过程创建了一个函数的活动对象,作用域链的最前端指向这个对象。

函数读取写入值,在作用域链里面查找。

函数执行完毕返回值后:执行环境、作用域链和活动对象一并销毁。

理解了这些之后,考察下原书的代码:

function createCompare(property){
    return function(obj1,obj2){
        var value1=obj1.property;
        var value2=obj2.property;
        
        if (value2 < value1){
            return 1;
        } else if (value2 >value1){
            return 1;
        } else {
            return 0;
        }
    };
}

var compareNames = createCompare("name");
var result = compareNames({name : "mars1"},{name : "mars2"});

其中,createCompare 函数返回了一个匿名函数,这个匿名函数就是一个闭包。它引用了createCompare函数的参数变量property。

创建compareNames 变量的时候,就创建了createCompare函数的活动变量:其中property = name etc. 同时返回了匿名函数给compareNames变量,它也有自己的执行环境与作用域链,作用域链引用了创建的compareNames活动对象。

result 定义过程,创建了compareNames的活动对象,其中obj1 = {name : "mars1"} etc.

这样,为result 赋值的compareNames函数执行环境的作用域链如下:

compareNames活动对象 → createCompare活动对象 → 全局对象。

那么问题来了,这个闭包是怎么导致占用更多内存的?

函数执行完毕,compareNames 变量并未消失,不会被垃圾回收,而它指向的闭包(匿名函数)的作用域链引用着createCompare 函数的活动变量。所以createCompare函数虽然执行完毕返回了匿名函数,但是它的活动对象并不会和执行环境、作用域链一样被销毁,因为还有compareNames的作用域链在引用。这样就相当于闭包携带了包含它的函数活动对象。

因此要释放compareNames携带的作用域,必须手动解除引用:

var compareNames = null;

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81593.html

相关文章

  • [学习笔记] JavaScript 闭包

    摘要:但是,必须强调,闭包是一个运行期概念。通过原型链可以实现继承,而与闭包相关的就是作用域链。常理来说,一个函数执行完毕,其执行环境的作用域链会被销毁。所以此时,的作用域链虽然销毁了,但是其活动对象仍在内存中。 学习Javascript闭包(Closure)javascript的闭包JavaScript 闭包深入理解(closure)理解 Javascript 的闭包JavaScript ...

    sunsmell 评论0 收藏0
  • JavaScript学习笔记 - 变量、作用域与内存问题

    摘要:语句中的块语句对来说,将会指定对象添加到作用域链中。在严格模式下,初始化未经声明的变量会导致错误。查询标识符搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。 本文记录了我在学习前端上的笔记,方便以后的复习和巩固。 4.1基本类型和引用类型的值 ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型指的是简单的数据段,而引用类型值指那些可...

    lavnFan 评论0 收藏0
  • 前端基础进阶(四):详细图解作用域链闭包

    摘要:之前一篇文章我们详细说明了变量对象,而这里,我们将详细说明作用域链。而的作用域链,则同时包含了这三个变量对象,所以的执行上下文可如下表示。下图展示了闭包的作用域链。其中为当前的函数调用栈,为当前正在被执行的函数的作用域链,为当前的局部变量。 showImg(https://segmentfault.com/img/remote/1460000008329355);初学JavaScrip...

    aikin 评论0 收藏0
  • JavaScript高级程序设计》(第3版)读书笔记 第7章 函数表达式

    摘要:定义函数表达式的方式有两种函数声明。不过,这并不是匿名函数唯一的用途。可以使用命名函数表达式来达成相同的结果闭包匿名函数和闭包是两个概念,容易混淆。匿名函数的执行环境具有全局性,因此其对象通常指向通过改变函数的执行环境的情况除外。 定义函数表达式的方式有两种: 函数声明。它的重要特征就是 函数声明提升(function declaration hoisting) 即在执行代码之前会...

    邹立鹏 评论0 收藏0
  • 【进阶2-3期】JavaScript深入之闭包面试题解

    摘要:闭包面试题解由于作用域链机制的影响,闭包只能取得内部函数的最后一个值,这引起的一个副作用就是如果内部函数在一个循环中,那么变量的值始终为最后一个值。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第二期,本周的主题是作用域闭包,今天是第8天。 本计划一共28期,每期重点攻克一个面试重难点,如果你还不了...

    alanoddsoff 评论0 收藏0

发表评论

0条评论

HmyBmny

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<