# 闭包
🔥JavaScript 的静态作用域链与“动态”闭包链 (opens new window)
个人觉得闭包没有那么复杂,本质就是上级作用域内变量的生命周期,因为被下级作用域内引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完以后才正常得到释放
# 什么是闭包 解决了什么问题
谈闭包 先要谈作用域
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行
一个函数执行完成以后 在某个时间 另外一个函数执行会用到第一个函数内部的作用域变量 这就是闭包
只要使用了回调函数,实际上就是在使用闭包! 因为回调的作用就是等待被触发 触发就会使用当时函数作用域
# 循环和闭包
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i)
}, i * 1000)
}
缺陷是我们试图假设循环中的每个迭代在运行时都会给自己“捕获”一个 i 的副本。但是根据作用域的工作原理,实际情况是尽管循环中的五个函数是在各个迭代中分别定义的,但是它们都被封闭在一个共享的全局作用域中,因此实际上只有一个 i。
立即执行函数会自己形成一个词法作用域
https://weread.qq.com/web/reader/8c632230715c01a18c683d8ke3632bd0222e369853df322
# 模块(闭包的应用)
如果要更简单的描述,模块模式需要具备两个必要条件。
- 必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)
- 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。
TIP
回调 和 模块 是 闭包的两大模式
# 动态作用域
主要区别:词法作用域是在写代码或者说定义时确定的,而动态作用域是在运行时确定的。(this 也是!)词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。
词法作用域 静态作用域 书写的时候就确定了变量的一个查找方式
this 动态 需要按照运行时候调用的情况去分别找到上下文
function foo() {
const a = 12
return function bar() {
console.log(a)
}
}
const bar = foo()
理解为一个背了个背包
一个函数(foo)被调用,返回了另一个函数时(bar)这个函数(bar)作用域存在 foo 的变量对象 导致能在非 foo 的执行上下文中访问 a 这个变量