手机版

JavaScript中闭包的详细介绍

时间:2021-10-15 来源:互联网 编辑:宝哥软件园 浏览:

闭包是JavaScript中的一个重要特性,它最大的功能就是保存函数运行过程中的信息。在JavaScript中,闭包的很多特性来自函数调用过程中的作用域链。

函数调用对象和变量的范围链。

对于JavaScript中的每个函数调用,JavaScript将创建一个本地对象来存储函数中定义的本地变量。如果函数内部有一个嵌套函数,JavaScript将在已经定义的本地对象之上定义一个嵌套的本地对象。对于一个函数,嵌套函数定义的层数和嵌套局部对象的层数一样多。本地对象叫做“函数调用对象”(ECMAScript 3中的“call object”,ECMAScript 5中改名为“声明性环境记录”,不过我觉得ECMAScript 3中的名字更容易理解)。以下面的函数调用为例:

复制代码如下: function f(x){ var a=10;返回一个* x;} console . log(f(6));//60

在这个简单的例子中,当调用f()函数时,JavaScript会创建一个f()函数的调用对象(姑且称之为f_invokeObj),f_invokeObj对象内部有两个属性:a和x;当f()运行时,a的值是10,x的值是6,所以最终的返回结果是60。如下图:

当存在函数嵌套时,JavaScript将创建多个函数调用对象:

复制代码如下: function f(x){ var a=10;返回a * g(x);函数g(b){ return b * b;} } console . log(f(6));//360

本例中,调用f()函数时,JavaScript会创建f()函数的调用对象(f_invokeObj),里面有a和x两个属性,值为10,x值为6;在运行f()的同时,JavaScript会解析定义f()函数中的g()函数,并创建g()的调用对象(g_invokeObj),该对象内部有一个属性b,b的值与传入的参数x相同,为6,因此最终返回结果为360。如下图:

如您所见,函数调用对象形成了一个链。当嵌入式函数g()运行需要获取变量值时,会从最近的函数调用对象开始搜索。如果找不到,会沿着函数调用对象链在更远的调用对象中搜索,称为“变量范围链”。如果同一个变量出现在两个函数调用对象中,函数将采用调用对象中最接近自身的变量值:

复制代码如下: function f(x){ var a=10;返回a * g(x);函数g(b){ var a=1;返回b * b * a;} } console . log(f(6));//360,不是3600

在上例中,变量a存在于g()函数的调用对象(g_invokeObj)和f()函数的调用对象(f_invokeObj)中,a的值不同。运行g()函数时,g()函数内部使用的a的值为1,而g()函数外部使用的a的值为10。此时的函数调用对象链如下:

什么是结束?

在JavaScript中,所有的函数都是对象,在定义函数时,会生成相应的函数调用对象链。每个函数定义对应一个函数调用对象链。只要函数对象存在,对应的函数调用对象就存在。一旦某个函数不再使用,相应的函数调用对象将被垃圾收集。函数对象和函数调用对象链之间的一对一组合称为“闭包”。在上面f()函数和g()函数的例子中,有两个闭包:f()函数对象和f_invokeObj对象形成一个闭包,而g()函数对象和g_invokeObj-f_invokeObj对象链一起形成第二个闭包。当执行g()函数时,g()闭包被垃圾收集,因为不再使用g()函数。之后,当f()函数被执行时,f()闭包也因为同样的原因被垃圾收集。

从闭包的定义可以得出,所有的JavaScript函数在定义之后都是闭包——因为所有的函数都是对象,所有的函数在执行之后都有对应的调用对象链。

然而,真正让闭包发挥作用的是嵌套函数。由于嵌入式函数只有在外部函数运行时才定义,因此存储在嵌入式函数闭包中的变量值(尤其是外部函数的局部变量值)就是这个运行过程中的值。只要嵌入的函数对象还存在,它的闭包还会存在(闭包中的变量值根本不会改变),从而达到保存函数运行过程信息的目的。考虑以下示例:

复制的代码如下: var a=' external ';函数f(){ var a=' inside ';函数g(){ return a;}返回g;}var结果=f();console . log(result());//内部

在本例中,当f()函数运行时,定义了g()函数,同时创建了g()函数的闭包。g()闭包包含g_invokeObj-f_invokeObj对象链,因此在f()函数执行期间变量a的值被保存。当执行console.log()语句时,g()闭包仍然存在,因为g函数对象仍然存在。当运行这个仍然存在的G函数对象时,JavaScript将使用仍然存在的G()闭包,并从中获取变量A的值(“内部”)。

版权声明:JavaScript中闭包的详细介绍是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。