Javascript作用域闭包问题

JavaScript中闭包无处不在,你只需要能够识别并拥抱它。

来自《你不知道的JavaScript》(上卷)

定义:当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

另一种定义:闭包是引用了自由变量的函数,并且自由变量即使离开了创建环境,也可以和函数一起存在。本质:是作用域链。

闭包的应用:

  1. 减少全局变量的定义;
  2. 封装对象的成员;

闭包的缺点:

  1. 内存无法释放;
  2. 逻辑错误;

  function foo() {
var a = 2;
function bar() {
console.log( a ); // 2
}
return bar;
}
var baz = foo();
baz();//2 闭包产生的效果

函数bar()的词法作用域能够访问foo()的内部作用域。然后我们将bar()函数本身当作一个值类型进行传递。在这个例子中,我们将bar 所引用的函数对象本身当作返回值。

在foo() 执行后,其返回值(也就是内部的bar() 函数)赋值给变量baz 并调用baz(),实际上只是通过不同的标识符引用调用了内部的函数bar()。

bar() 显然可以被正常执行。但是在这个例子中,它在自己定义的词法作用域以外的地方执行。

在foo() 执行后,通常会期待foo() 的整个内部作用域都被销毁,因为我们知道引擎有垃圾回收器用来释放不再使用的内存空间。由于看上去foo() 的内容不会再被使用,所以很自然地会考虑对其进行回收。

而闭包的“神奇”之处正是可以阻止这件事情的发生。事实上内部作用域依然存在,因此没有被回收。谁在使用这个内部作用域?原来是bar() 本身在使用。

拜bar() 所声明的位置所赐,它拥有涵盖foo() 内部作用域的闭包,使得该作用域能够一直存活,以供bar() 在之后任何时间进行引用。

bar() 依然持有对该作用域的引用,而这个引用就叫作闭包。

因此,在几微秒之后变量baz 被实际调用(调用内部函数bar),不出意料它可以访问定义时的词法作用域,因此它也可以如预期般访问变量a。

这个函数在定义时的词法作用域以外的地方被调用。闭包使得函数可以继续访问定义时的词法作用域。

 

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注