【javascript】深入理解闭包

一、什么是闭包

匿名函数经常被误认为闭包(closure)。闭包是指那些引用了一个函数作用域中变量的函数,通常是嵌套函数实现的。


二、如何理解闭包

1. 复习作用域链

理解作用域链创建和使用的细节对理解闭包非常重要。

  1. 调用函数的时候,会为这个函数创建一个执行上下文。
  2. 复制函数的[[Scopes]]来创建作用域链。
  3. 创建活动对象保存arguments和其他变量和函数。
  4. 将活动对象推入到作用域链的前端。

2. 实例分析

仅仅用几行文字很难去理解这个闭包,那么就一起来分析一下下面的这个实例来更好地理解闭包。

  function fn1() {
    var a = 2

    function fn2() {
      a++
      console.log(a)
    }

    return fn2
  }
  var f = fn1()
  f() // 3
  f() // 4
  1. 在执行fn1之前,对fn2的[[Scopes]]属性初始化,其值为上一级的作用域链。如下图所示:在这里插入图片描述
  2. 这样这个函数就能访问带fn1可以访问到的所有变量。
  3. return了之后,虽然fn1执行结束,但是fn1的活动对象并不会被销毁,这是因为fn2函数的作用域链仍然对其有引用。销毁的只是fn1的执行上下文。
    下图展示了作用域关系。
    在这里插入图片描述

3. 普通函数与闭包

  1. 在没有闭包的情况下,fn1函数执行完毕,fn1的执行上下文被销毁,fn1中的活动对象没有被引用,最后被垃圾回收程序释放掉。
  2. 在闭包中,函数执行完后,虽然fn1的执行上下文被销毁,但是fn1的活动对象仍然被引用,所以fn1的活动对象并没有被回收。

4. 销毁匿名函数

上例,通过设置f = null,解除对fn2函数的引用,从而让垃圾回收程序可以将内存释放掉。接着,作用域链也被销毁,其他作用域(除全局作用域以外)都被销毁了。

5. 产生闭包的条件

  • 函数嵌套
  • 内部函数引用外部函数的局部变量
  • 使用内部函数

6. 闭包的作用

  1. 延长外部函数变量对象的声明周期
  2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)

三、趁热打铁

练习1

 function fun(n, o) {
    console.log(o)
    return {
      fun: function (m) {
        return fun(m, n)
      }
    }
  }
  var a = fun(0)
  a.fun(1)
  a.fun(2)
  a.fun(3)

  var b = fun(0).fun(1).fun(2).fun(3) 

  var c = fun(0).fun(1)
  c.fun(2)
  c.fun(3) 

练习2

 function Foo() {
    getName = function () { alert (1); };
    return this;
  }
  Foo.getName = function () { alert (2);};
  Foo.prototype.getName = function () { alert (3);};
  var getName = function () { alert (4);};
  function getName() { alert (5);}

  //请写出以下输出结果:
  Foo.getName();
  getName();
  Foo().getName();
  getName();
  new Foo.getName();
  new Foo().getName();
  new new Foo().getName();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值