作用域闭包
# 作用域闭包
IIFE 模式。通常认为 IIFE 是典型的闭包例子,我并不是很同意这个观点。严格来讲它并不是闭包。
因为函数并不是在它本身的词法作用域以外执行的。它在定义时所在的作用域中执行
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
1
2
3
4
5
6
7
2
3
4
5
6
7
bar() 依然持有对该作用域的引用,而这个引用就叫作闭包。
# 循环和闭包
要说明闭包,for 循环是最常见的例子
缺陷是我们试图假设循环中的每个迭代在运行时都会给自己“捕获”一个 i 的副本。但是 根据作用域的工作原理,实际情况是尽管循环中的五个函数是在各个迭代中分别定义的, 但是它们都被封闭在一个共享的全局作用域中,因此实际上只有一个 i。
IIFE 会通过声明并立即执行一个函数来创建作用域。
# 重返块作用域
本质上这是将一个块转换成一个可以被关闭的作用域。
使用 IIFE 在每次迭代时都创建一个新的作用 域。换句话说,每次迭代我们都需要一个块作用域。
变量在循环过程中不止被声明一次,每次迭代都会声明。随 后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。
for (let i=1; i<=5; i++) {
setTimeout( function timer() { console.log( i );
}, i*1000 );
}
1
2
3
4
2
3
4
# 模块
最常见的实现模块模式的方法通常被称为模块暴露
模块模式需要具备两个必要条件。
- 必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块 实例)。
- 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并 且可以访问或者修改私有的状态
# 小结
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时 就产生了闭包。
模块有两个主要特征:
(1)为创建内部作用域而调用了一个包装函数;(2)包装函数的返回 值必须至少包括一个对内部函数的引用,这样就会创建涵盖整个包装函数内部作用域的闭 包。