面试题准备(五):闭包

闭包

定义 一 — 内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
定义 二 — 1. 即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)2. 在代码中引用了自由变量
广义闭包:所有的函数。因为它们都在创建的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域。

复习 — 函数执行过程

var scope = "global scope"
function checkscope(){
    var scope = "local scope"
    function f(){
        return scope
    }
    return f
}

var foo = checkscope()
foo() // local scope
  1. 创建全局执行期上下文,压入执行期上下文栈
    ECStack = {
    globalContext
    }
  2. 全局执行期上下文初始化,全局变量赋值等
    globalContext = {
    GO = {
    ​ scope: undefined,
    ​ checkscope: function checkscope() {},
    ​ foo: undefined
    }
    }
  3. 函数 checkscope 执行,创建函数的执行期上下文,压入执行期上下文栈
    ECStack = {
    ​ checkscopeContext
    ​ globalContext
    }
  4. checkscope 函数执行期上下文初始化,变量赋值、作用域链、this
    checkscopeContext {
    AO: {
    ​ scope: undefined,
    ​ f: function f() {}
    },
    [[scope]]: [GO]
    }
  5. checkscope 执行完毕,其执行期上下文从执行期上下文栈弹出
    ECStack = {
    ​ globalContext
    }
  6. f 函数执行,创建 f 的执行期上下文,压入执行期上下文栈
    ECStack = {
    ​ fContext
    ​ globalContext
    }
  7. f 执行期上下文初始化
    fContext = {
    AO,
    ​ [[scope]]: {
    ​ checkscopeAO,
    ​ GO
    ​ }
    }
  8. f 执行完毕,f 的执行期上下文出栈

从上面的分析可以看到,在 checkscope 执行过程中,f 函数在定义时会创建 f 函数的执行期上下文,会将 checkscope 函数的作用域链拷贝给自身。此后,虽然 checkscope 函数的执行期上下文随着函数执行完毕被销毁,但 f 函数的执行期上下文中仍保有 checkscope 的作用域链,f 函数可通过自身的作用域链找到它,这就是闭包。

试一试

function test() {
	var arr = [];
	for (var i = 0; i < 3; i++) {
	    arr[i] = function () {
	        console.log(i);
	    }
	}
	return arr;
}

var arr = test()
arr[0]()
arr[1]()
arr[2]()

答案全为 3

  1. 全局执行期上下文创建并压入执行期上下文栈
    ECStack = {
    ​ globalContext
    }
  2. 全局执行期上下文初始化
    globalContext = {
    ​ GO = {
    ​ arr: undefined
    ​ }
    }
  3. test 函数创建执行期上下文并压入执行期上下文栈
    ECStack = {
    ​ testContext
    ​ globalContext
    }
  4. test 函数执行期上下文初始化
    testContext = {
    ​ AO: {
    ​ arr: undefined
    ​ },
    ​ [[scope]]: [GO]
    }
  5. test 函数执行,每个 for 循环为 arr[i] 函数创建并初始化一个执行期上下文
    test 函数执行期上下文
    testContext = {
    ​ AO: {
    ​ arr: [func …],
    ​ i: 3
    ​ },
    ​ [[scope]]: [GO]
    }
    arr[i] 函数执行期上下文
    arr[i]Context = {
    ​ [[scope]]: [testContext.AO, GO]
    }
  6. test 函数执行完,其执行期上下文销毁,但 arr[i] 仍保有 test 函数的 AO
  7. test[i] 函数执行,由于在该函数执行期上下文中没有变量 i 故在其作用域链顶端开始向下搜索第一个变量 i,最终在 test 的 AO 中找到 i 为 3 并打印
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值