作用域
作用域是程序源代码中定义的范围。JavaScript采用词法作用域,也就是静态作用域。所谓词法作用域就是在函数定义的时候就已经确定了。
let value = 1
function foo(){
console.log(value)
}
function bar(){
let value = 2
foo()
}
bar() // 1
变量对象是当前代码段中,所有的变量(变量、函数、形参、arguments)组成的一个对象。变量对象分为全局变量对象和局部变量对象。全局简称为Variable Object VO,函数由于执行才被激活称为Active Object AO。
作用域链。在js中,函数存在一个隐式属性[[scopes]],这个属性用来保存当前函数的执行上下文环境,由于在数据结构上是链式的,因此也被称作是作用域链。我们可以把它理解为一个数组,可以理解为是一系列的AO对象所组成的一个链式结构。
作用域链的变量只能向上访问,直到访问到 window 对象终止。作用域链执行完会销毁。
function fn (){
}
console.dir(fn)
function fn (){
console.dir(fn)
}
fn()
let global
function a() {
let aa = 123
function b() {
let bb = 234
}
b()
}
a()
- 当 a 定义时,VO 包含 this(window), a(function), global
- a 调用时,加入 a 的 AO 包含 this(window), arguments, b(function)
- b 函数生成(a 函数的调用导致 b 函数的生成)
- b 函数调用,b 函数的 AO 包含 this(window), arguments, bb
闭包
之所以没有及时被垃圾回收机制回收,是因为作用域链没有断裂。
let global
function a() {
let aa = 123
function b() {
console.log(aa)
}
return b
}
let res = a()
res()
闭包实际应用
回调函数,防抖节流,定时器传参,手写 js (bind…),封装某些方法。
一道笔试题
function add(n) {
let sum = n;
function innerAdd(nextNum) {
if (nextNum !== undefined) {
sum += nextNum;
return innerAdd;
} else {
return sum;
}
}
return innerAdd;
}
console.log(add(1)(2)()); // 3
console.log(add(1)(2)(3)(4)()); // 10
console.log(add(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)()); // 10