JS三座大山_闭包
JS三座大山_闭包
摘自吴留坡《原来JavaScript的闭包是这么回事!》
一、相关概念
1.执行上下文
- 在执行JS代码时候的运行环境称为执行上下文。包括:全局代码——首次执行代码的默认环境;函数代码——每当执行流程进入函数体时。
- 执行上下文即当前代码的执行环境或作用域。
2.执行过程
- 全局:启动程序后,从全局执行上下文开始,在全局执行上下文中声明的变量为全局变量
- 函数体:调用函数时,JS创建一个本地执行上下文——本地执行上下文拥有自己的变量集,即函数的局部变量——新的执行环境被抛到执行栈上。
- (执行栈为用于跟踪程序执行位置的机制)
- 函数遇到return或结束符号时:本地执行上下文从执行栈跳出——函数将返回值发送给调用上下文(调用上下文是调用此函数的执行上下文,可以是全局执行上下文,也可以是另一个本地执行上下文)——本地执行上下文被销毁(局部变量被销毁)
3.词法作用域
-
变量查找过程:本地执行上下文(局部变量)——调用上下文(局部变量/全局变量)——全局上下文(全局变量)
-
一个函数可以访问在其调用上下文中定义的变量,此种现象称为词法作用域。
4.闭包原理
- 当声明一个函数时,它包含一个函数定义和一个闭包。闭包是函数创建时声明的变量。
function createFn(){
let counter = 0;
const myFn = function(){
counter = counter + 1;
return counter;
}
return myFn;
}
- 全局范围中创建的函数也会创建一个闭包,但由于其是全局的,可以访问全局范围内所有变量,就无所谓闭包不闭包了。
- 当一个函数返回另一个函数,并使用其调用上下文中变量时,才会真正涉及闭包。返回的函数可以访问仅存在于其闭包中的变量。
- 当创建和传递一个函数或将其从另一个函数返回时,这个函数就带有一个闭包,闭包中包含了所有在创建函数时声明的变量。
二、对闭包的理解
闭包:
重用局部变量,并保护该局部变量不受污染的一种机制。(既有全局变量可重复使用的优点,又规避了全局变量易受污染的缺点)
作用:
- 创建私有变量
- 延长私有变量的生命周期
一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的词法环境依然存在,以达到延长变量生命周期的目的
使用:
- 定义外层函数:定义受保护的局部变量(即闭包)——返回一个专门操作局部变量的内部函数对象
- 调用外层函数,获得返回的内部函数对象
- 使用返回的内部函数对象,操作受保护的局部变量——唯一路径
结论:
- 同一次外层函数调用返回的多个内层函数对象共用一个受保护的变量
- 先后两次外层函数调用返回的内层函数,分别使用各自受保护的变量副本,互不影响。
三、闭包使用场景
1.setTimeout回调函数传值问题
2.回调函数
3.封装变量:公有方法中访问私有变量
4.模拟私有方法
- JS中没有支持声明的私有变量,但我们可以用闭包来模拟私有方法