摘要:第二段代码由于匿名函数并没有被外的其他地方所引用,所以在函数执行完毕后,其活动对象也跟随的执行环境的销毁而销毁。
话不多说先来看两段代码
function a(){ var num=10; return function(){ console.log(num++) } } var b=a(); b(); //10 b(); //11 b(); //12 b=null; //手动释放内存,消除对匿名函数的引用
function a(){ var num=10; return function(){ console.log(num++) } } a()(); //10 a()(); //10 a()(); //10
下面开始讲解代码:
在讲解之前,首先请了解一下关于函数作用域方面的知识,可以参考本人之前写的一片短文https://segmentfault.com/a/11...
//当函数a定义时 会创建一个[[scope]]属性,仅供javascript引擎内部使用 //伪代码 a.[[scope]]={ GO:{ //全局对象globel object this:window, window:{...}, document:{...}, a:(function) ... } }
当函数a调用的时候,会创建一个a的执行环境,每个执行环境对应一个变量对象。首先会创一个它自己的活动对象【Activation Object】(这个对象中包含了this、参数(arguments)、局部变量(包括命名的参数)的定义,当然全局对象是没有arguments的)和一个变量对象的作用域链[[scope chain]],然后,把这个执行环境的[[scope]]按顺序复制到[[scope chain]]里,最后把这个活动对象推入到[[scope chain]]的顶部。这样[[scope chain]]就是一个有序的栈,这样保了对执行环境有权访问的所有变量和对象的有序访问。
//函数调用时候 a.ex={ //a的执行环境,包括a的活动对象和a的作用域链 AO:{ this:window, arguments:[], num:undefined }, [[scope chain]]:{ AO:当前函数活动对象, GO:{...} //全局对象,从a.[[scope]]中复制过来的 } //进入a的执行环境时,匿名函数被定义. 匿名函数.[[scope]]={ AO:{ //函数a的活动对象 this:window, arguments:[], num:undefined }, GO:{...} }
关键点来了
上述两段代码中:
第一段代码在执行a()的时候,将a函数返回的匿名函数赋给了变量b,并且连续调用三次b
第二段代码在执行a()的时候,没有对a函数返回的匿名函数进行赋值。
在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。
第一段代码因为函数a的活动对象被匿名函数的[[scope]]引用,匿名函数又被a外的变量b引用,所以在全局环境下始终保持对a活动对象的引用,所以a的活动对象无法被回收。
第二段代码由于匿名函数并没有被a外的其他地方所引用,所以在函数a执行完毕后,其活动对象也跟随a的执行环境的销毁而销毁。
用图表示
值得注意的是,虽然执行环境和函数scope属性中都保存这作用域链,但这两个并不是一个性质的。
明确一点区别
[[Scope]]属性是函数创建时产生的,会一直存在
而执行环境在函数执行时产生,函数执行结束便会销毁
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/81105.html
摘要:之前一篇文章我们详细说明了变量对象,而这里,我们将详细说明作用域链。而的作用域链,则同时包含了这三个变量对象,所以的执行上下文可如下表示。下图展示了闭包的作用域链。其中为当前的函数调用栈,为当前正在被执行的函数的作用域链,为当前的局部变量。 showImg(https://segmentfault.com/img/remote/1460000008329355);初学JavaScrip...
摘要:关于循环和闭包当循环和闭包结合在一起时,经常会产生让初学者觉得匪夷所思的问题。闭包是一把双刃剑是比较难以理解和掌握的部分,它十分强大,却也有很大的缺陷,如何使用它完全取决于你自己。 在谈闭包之前,我们首先要了解几个概念: 什么是函数表达式? 与函数声明有何不同? JavaScript查找标识符的机制 JavaScript的作用域是词法作用域 JavaScript的垃圾回收机制 先来...
摘要:然而,引擎很可能虽然这要看具体实现将会仍然将这个结构保持一段时间,因为函数在整个作用域上拥有一个闭包。 内容 平时编写代码的时候很少关注细节,对javascript深层也没具体了解,下面针对平时写代码的形式分析、调整完善自己的代码,这里以一个简单例子分析js作用域和垃圾回收机制,通过块级作用域处理一些细节,提升自己代码性能。 普通案例 在日常中最常见的代码编写方式: function ...
摘要:因此,所有在方法中定义的变量都是放在栈内存中的当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用因为对象的创建成本通常较大,这个运行时数据区就是堆内存。 上一篇:《javascript高级程序设计》笔记:继承近几篇博客都会围绕着图中的知识点展开 showImg(https://segmentfault.com/img/bVY0C4?w=1330&h=618);...
阅读 2739·2021-11-19 11:30
阅读 2996·2021-11-15 11:39
阅读 1748·2021-08-03 14:03
阅读 1953·2019-08-30 14:18
阅读 2011·2019-08-30 11:16
阅读 2102·2019-08-29 17:23
阅读 2530·2019-08-28 18:06
阅读 2500·2019-08-26 12:22