JavaScript-闭包和作用域
1 | var x = 1 |
闭包
闭包是纯函数式编程语言的主要特征之一。
闭包允许函数访问并操作函数外的变量,只要闭包或变量存在于声明函数时所在的作用域内,闭包即可使用函数使用这些变量或函数。
闭包 demo
1 | var outerValue = 'outerValue' |
闭包创建了被定义时的作用域内的变量或函数的安全汽泡,函数获得了执行时的引用。因此,即使 outerFn 函数执行结束被销毁,但引用存在。
每一个通过闭包访问变量的函数都有作用域链,作用域包含闭包的全部信息
使用闭包,所有信息都会存在内存中。直到 Javascript 引擎确保这些信息不再使用,即可以进行安全的垃圾回收或卸载页面才会清理。
闭包 —— 封装私有变量
1 | // 创建构造函数 |
JavaScript 中没有真正的私有变量属性,只是通过闭包实现一种可接受的“私有变量”方案
1 | // 创建构造函数 |
总结
JavaScript 允许将一个对象的属性复制给另外一个对象,导致如 demo,name 属性并非真正私有变量,但可成为一种隐藏信息的有用方式
闭包 —— 回调函数
1 | <div id="box1"></div> |
1 | function animateIt(elementId) { |
闭包内部的函数不仅可以在闭包创建的时刻访问这些变量,而且当闭包内部的函数执行时,还可以更新这些变量的值。闭包不是在创建的那一时刻的状态的快照,而是一个真实的状态封装,只要闭包存在,就可以对变量进行修改。
结合词法环境,理解闭包
作用域
在程序的特定部分中,标识符的可见性。作用域是程序的一部分,特定名字绑定特定的变量。
通过执行上下文来跟踪代码 —— Javascript 引擎如何跟踪函数的执行并回到函数的位置
Javascript 中,代码执行的基础单元是函数。
Javascript 中每条语句的执行,都处于特定的执行上下文。Javasacript 分为两种代码,全局代码和函数。同样,执行上下文也分为函数执行上下文和全局执行上下文。全局执行上下文只有一个,当 Javascript 代码执行时即创建。函数执行上下文可有多个,每调用一个函数,创建一个新的函数执行上下文。
函数执行上下文
1 | function user() { |
Javascript 是单线程模型,同一时刻只能执行特定的代码
Javascript 引擎使用执行上下文跟踪函数的执行。使用执行上下文栈(调用栈)跟踪执行上下文。具体如下:
- Javascript 程序开始,全局执行上下文已创建,开始执行全局执行上下文
user()
函数调用,user
执行上下文入栈,全局执行上下文暂停
getOrderList()
函数调用后,user()
函数执行上下文暂停,getOrderList()
函数执行上下文入栈
getOrderList()
函数执行完成后,getOrderList
函数上下文出栈,user
函数恢复执行
user
函数执行完后,user
函数上下文出栈,全局执行上下文恢复执行
使用词法环境跟踪变量的作用域
词法环境(lexical enviroment)是 JavaScript 引擎内部用来跟踪标识符与特定变量之间的映射关系。
词法环境,即作用域(scopes)是 JavaScript 作用域的内部实现机制。
函数、代码片断、try-catch 语句可以具有独立的标识映射表。
代码嵌套与词法环境
1 | var userId = 0 |
词法环境主要基于代码嵌套,通过代码嵌套可以实现代码结构包含另一代码结构。
无论何时创建函数都会创建一个与之关联的词法环境,并存在函数的[[Eviroment]]内部属性上。也会创建内部环境环境的引用。
JavaScript 引擎调用函数内置的[[Eviroment]]属性与创建时的环境相关联。
理解 JavaScript 变量
词法环境中注册标识符 —— 在函数声明之前调用函数
1 | console.log(userId, getUserInfo, arrowFn, statementFn) // undefined ƒ getUserInfo() {} undefined undefined |
Uncaught TypeError: statementFn is not a function
JavaSript 代码的执行分两个阶段进行
第一阶段 —— 注册当前词法环境中声明的变量和函数并赋初值
第二阶段 —— 赋值,执行
总结
词法环境注册标识符 —— 函数重载
1 | console.log('fn', fn) // fn ƒ fn() {} |
第一阶段,JavaScript 引擎进行代码扫描,合建词法环境,注册变量、声明函数
第二阶段,赋值并执行
通过词法环境理解闭包
1 | function Counter() { |
词法环境用于保持跟踪函数中定义的变量