JavaScript进阶笔记(二):作用域链和闭包
JavaScript进阶笔记(二):作用域链和闭包
镇长一、闭包
闭包是指有权访问另一个函数作用域中的变量的函数。 — 红宝书
闭包是一个函数;能够访问另一个函数作用域中的变量。
1.1 闭包的特点
- 闭包可以访问当前函数以外的变量。
- 即使外部函数已经返回,闭包仍能访问外部函数定义的变量。(作用域链)
- 闭包可以更新外部变量的值。
二、作用域链
当访问一个变量时,解释器会在当前作用域中查找标示符,如果没找到就去父作用域找,直到找到或者抛出 ReferenceError,最顶端是全局对象。这就是作用域链。
作用域链和继承查找的区别:继承查找在当前对象和原型都找不到,会返回 undefined;但作用域链查找找不到则会抛出 ReferenceError。
三、测试题
1 | var data = []; |
循环结束后,全局执行上下文 VO 是:
1 | globalContext = { |
执行 data[0] 函数时,作用域链为:
1 | data[0]Context = { |
自身没有 i 变量,向上查找,此时全局上下文中 i 为 3。
3.1 解决方法
不去读全局而是维护一份副本。
3.1.1 立即执行
1 | var data = []; |
3.1.2 匿名函数赋值
1 | var data = []; |
使用ES6中的 let
1 | var data = []; |
四、作用域链与闭包
1 | var scope = 'global scope' |
调用栈执行顺序:
1 | Stack.push(<global>) |
函数 f 的执行是在 checkscope函数上下文被销毁之后,那么为何还能读取到 scope 变量?
函数f执行后会维护一个作用域链,会指向checkscope 作用域,作用域链是一个数组。
如下:
1 | fContext = { |
所以指向关系是当前作用域 --> checkscope作用域--> 全局作用域
,即使 checkscopeContext 被销毁了,但是 JavaScript 依然会让 checkscopeContext.AO
(活动对象) 活在内存中,f 函数依然可以通过 f 函数的作用域链找到它,这就是闭包实现的关键