到底该如何理解闭包?

2023-02-05 0 669

旋量群始终是 JavaScript 中两个十分关键的基本概念。从前始终极难认知那个基本概念,主要就是对 JavaScript 中的继续执行基本原理不熟识。透过对后面继续执行语句和废弃物搜集的归纳,总算能对那个基本概念回去展开分析了。

上面是我的许多认知和归纳。

表述

旋量群是指无权出访另两个表达式返回值中的表达式的表达式。建立旋量群的最常用的形式,是在两个表达式外部建立另两个表达式。

他们举两个范例:

function outer(){ var a = 1; functioninner(){ console.log(a); } inner(); // 1}outer();

在 inner 表达式中,他们能透过返回值链出访到 a 表达式,因而这就能称得上形成了两个旋量群,即使 a 表达式是其它表达式返回值中的表达式。

到底该如何理解闭包?

总之这和他们平常碰到的许多旋量群难题可能将不太那样,但是那些难题的其本质只但是都是在现阶段表达式返回值中出访另两个表达式返回值中的表达式。

示例预测

上面我们上看两个经典之作的旋量群的范例:

function createFunctions(){ var result = new Array(); for(var i=0; i < 10; i++){ result[i] = function(){ console.log(i); } } return result; } var result = createFunctions(); result[0](); // 9 result[1](); // 9 result[2](); // 9 result[3](); // 9 result[4](); // 9 result[5](); // 9

他们建立了两个表达式用来建立两个表达式数组,希望数组中的每个表达式都打印自己的索引值,即位置0的表达式打印0,位置1的表达式打印1。但实际上最终每个表达式打印的都是10,这是为什么呢?上面他们从程序继续执行开始预测。

全局代码继续执行

首先在继续执行全局代码之前, JavaScript 引擎会首先对全局代码展开解析,建立全局继续执行语句 globalContext 。

1、首先会建立全局继续执行语句的第两个属性全局表达式对象 globalVO 。

// 省略全局对象其它属性globalContext.globalVO = { createFunctions: reference to function createFunctions,};

2、然后将 globalVO 压入全局语句返回值链的顶端。

globalContext.[[Scope]] = [ globalContext.globalVO ];

3、然后将全局语句的返回值链赋值给 globalVO 中所有的表达式的 [[Scope]] 属性。

createFunctions.[[Scope]] = globalContext.[[Scope]];

全局继续执行语句建立好后,进入到全局继续执行代码的继续执行阶段,首先将全局继续执行语句压入继续执行上下文栈中,然后按顺序依次继续执行代码。

1.在继续执行代码前判断得到全局继续执行语句中的 this 指向 globalVO;

2.继续执行代码 createFunctions();进入createFunctions()表达式继续执行阶段。

createFunctions() 表达式继续执行阶段

在继续执行 createFunctions() 表达式前,Javascript 引擎会先对 createFunctions 表达式代码展开解析,创建 createFunctions 表达式的继续执行语句 createFunctionsContext。

建立 createFunctions 表达式继续执行语句的活动对象 createFunctionsAO。

createFunctionsContext.createFunctionsAO = { result: undefined, i: undefined, };

复制 createFunctions 表达式的 [[Scope]] 属性,为表达式继续执行语句的返回值链赋值,然后将表达式继续执行语句的活动对象压入返回值链顶端。

createFunctionsContext.[[Scope]] = [ createFunctionsContext.createFunctionsAO, globalContext.globalVO ];

createFunctions 表达式继续执行语句建立后,进入表达式代码的继续执行阶段,将 createFunctionsContext 压入继续执行语句栈中,按顺序依次继续执行代码。

1、在继续执行代码前,根据表达式调用形式,判断得到 createFunctionsContext 的 this 指向为 globalVO。

2、继续执行第一行代码 var result = new Array(); ,为 createFunctionsAO 的 result 属性赋值。

createFunctionsContext.createFunctionsAO = { result: reference to Array result, i: undefined, };

3、然后继续执行 for 循环语句代码,继续执行第一次循环,i赋值为0,然后为每两个数组项建立两个表达式对象

createFunctionsContext.createFunctionsAO = { result: reference to Array result, i: 0, };

4、循环代码继续执行完后,此时的 createFunctionsAO 为

createFunctionsContext.createFunctionsAO = { result: reference to Array result, i: 9,};

5、然后继续执行代码return result;,返回表达式数组。

6、createFunctions 表达式的继续执行语句弹栈,控制权交回全局继续执行语句,接着继续执行代码 result0; ,进入 result[0] 表达式的继续执行阶段。

result[0]表达式继续执行阶段

在继续执行 result0 表达式前,Javascript 引擎会先对 result[0] 表达式代码展开解析,建立 result[0] 表达式的继续执行语句 result0Context。

1、建立 result0 表达式继续执行语句的活动对象 result0AO。

result0Context.result0AO = { };

2、复制 result0 表达式的 [[Scope]] 属性,为表达式继续执行语句的返回值链赋值,然后将表达式继续执行语句的活动对象压入返回值链顶端。

result0Context.[[Scope]] = [ result0Context.result0AO, createFunctionsContext.createFunctionsAO, globalContext.globalVO ];

result0 表达式继续执行语句建立后,进入表达式代码的继续执行阶段,将 result0Context 压入继续执行语句栈中,按顺序依次继续执行代码。

1)在继续执行代码前,根据表达式调用形式,判断得到 result0Context 的 this 指向为 globalVO。

2)重点来了,继续执行代码 console.log(i); ,首先 Javascript 引擎会搜寻现阶段表达式表达式对象,现阶段表达式的表达式对象找不到 i 值时,会根据返回值链搜寻其它表达式返回值中的表达式。

因而他们在 createFunctionsAO 中找到了 i 表达式,此时的 i 表达式保存的是 i 叠加后结果,因而表达式打印的结果为 9。这里他们还需注意的一点是一般来说。

在 createFunctions 表达式继续执行完后 createFunctionsAO 就应该销毁了,但是由于他们在 result0Context 的返回值链中保留了对它的引用,因而在废弃物搜集的时候,判断能透过引用找到该对象,因此它就不会被清除掉,而是继续保留在内存中,让他们出访。

3)代码继续执行完成后,继续继续执行后面 result1 表达式继续执行代码。

解决办法

那么他们如果想让那个表达式符合他们的预期的话,他们应该怎么办呢?他们能做一下这样的修改。

function createFunctions(){ var result = new Array(); for(var i=0; i < 10; i++){ result[i] = (function(num){ return function(){ console.log(num); } })(i); } return result; } var result = createFunctions(); result[0](); // 0 result[1](); // 1 result[2](); // 2 result[3](); // 3 result[4](); // 4 result[5](); // 5

相信透过上面的预测,大家应该能够明白这样写原因,这里就不再预测了。

写在最后

旋量群那个基本概念只但是涉及到的知识点很多,如果继续执行语句不熟识,对废弃物搜集机制不熟识,认知起来只但是是很模棱两可的。透过这样两个整体的预测,对闭包也有了两个更好的认知。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务