【总结】JavaScript 变量作用域和闭包
- Lexical Environment
- 每个运行的函数、代码块或脚本都有一个关联的 Lexical Environment 对象,它用来存储局部变量和函数声明。
- Lexical Environment 有两个组成部分:Environment Record(存储变量)和对外部 Lexical Environment 的引用。
- 函数在执行时会生成一个内部的 Lexical Environment 来存储局部变量和参数。
- 变量
- 变量实际上就是 Lexical Environment 的属性。读取/修改变量就是读取/修改这个对象的属性。
- 函数声明会被立即初始化,但 let/const 变量要到声明后才能读取。
- 块级作用域 - 在 {} 内声明的变量只在块内可见。
- 嵌套函数
- 嵌套函数可以访问外部函数的变量,这使其可以封装外部变量。
- 嵌套函数会通过 Environment 属性记住它被创建的位置,所以它总能访问该位置的外部变量。
- 闭包
- 闭包是可以记住外部变量并访问这些变量的函数。
- JavaScript 中所有函数都是天然的闭包,它们通过 Environment 属性实现。
- 垃圾回收
- 如果嵌套函数被引用,则外部 Lexical Environment 不会被回收。
- 但是如果外部变量没有被嵌套函数使用,引擎会对其进行优化,使其无法在嵌套函数中访问。
- 其他
- 理解 Lexical Environment 和闭包的工作原理可以更好地编写 JavaScript 代码。
- 嵌套函数和闭包在组织代码和封装变量方面很有用。
- 变量优化可能会使开发调试变得困难。