读《JavaScript高级程序设计》有感。
要弄清这个问题,先得了解JavaScript函数执行的工作过程。
文章原文
函数在被调用时,会创建一个函数的执行环境以及相应的作用域链,使用arguments和其他的命名参数来初始化函数的活动对象。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象始终处于第三位,。。。直到全局执行环境。
原文比较晦涩,结合实例研究比较清晰。
二话不说,直接创建一个函数。
let a = 1
function fn(){
let a = 2
console.log(a)
}
fn()
一眼可以看出输出是2。原理是什么呢。
然后我们根据书上的描述来刨析这个函数。首先是第一句话
函数在被调用时,会创建一个函数的执行环境以及相应的作用域链。
此时的内部应该是这样
第二步,初始化函数fn的执行环境。
然后是最后一句话。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象始终处于第三位,。。。直到全局执行环境。
那么在闭包中的情况就是这样
let a = 1
function fn(){
let a = 2
return (function () {
return a
})()
}
fn()
函数内又包含了一个匿名函数,那么这个匿名函数的执行环境如下。
匿名函数的执行环境 |
匿名函数的作用域链 |
匿名函数的作用域链如下
匿名函数的作用域链 | |
2 | 全局 |
1 | fn的活动对象 |
0 | 匿名函数的活动对象 |
函数fn执行后。匿名函数就可以访问在fn中定义的全部变量。而且fn在执行完成后,其活动对象也不会销毁,因为匿名函数的作用域链还在引用着这个对象。