1. ECMA语法词汇概念解释
1. 执行上下文(Execution Context)
- 定义:JavaScript代码执行的环境,每个函数调用都会创建一个新的执行上下文。
- 组成:
- 变量对象(VO)/词法环境(Lexical Environment) :保存变量、函数声明和参数。
- 作用域链(Scope Chain) :用于查找变量。
- this 值:当前执行上下文中
this的指向。
- 类型:
- 全局执行上下文(只有一个)
- 函数执行上下文(每次函数调用都会创建)
2. 执行上下文栈(Execution Context Stack / Call Stack)
- 定义:JS引擎用来管理执行上下文的栈结构,也叫调用栈。
- 作用:控制函数调用的顺序,先进后出(LIFO)。
- 过程:
- 当一个函数被调用时,新的执行上下文被推入栈顶。
- 函数执行完毕后,该上下文被弹出栈。
3. 作用域(Scope)
- 定义:变量或函数可访问的范围。
- 目的:控制变量的可见性和生命周期,防止命名冲突。
- 类型:
- 全局作用域(Global Scope) :
- 变量和函数在全局范围内声明,可以在代码的任何地方被访问。
- 这些变量和函数在整个程序运行期间都存在。
- 函数作用域(Function Scope) :
- 使用
var关键字声明的变量具有函数作用域,意味着它们只在声明它们的函数内部有效。 - 即使在嵌套的块(如循环或条件语句)中声明,这些变量也只在包含它们的最内层函数内可见。
- 使用
- 块级作用域(Block Scope) :
- 使用
let和const关键字声明的变量具有块级作用域,这意味着它们的作用范围是从声明的地方开始,直到包含它们的最近的闭合块结束。 - 块可以是任何用花括号
{}包围的代码段,例如循环体、条件语句等。
- 使用
- 模块作用域(Module Scope) :
- 随着ES6引入模块系统(
import和export),每个JavaScript模块都有自己的顶级作用域。 - 在模块的顶层声明的变量、函数、类等,默认情况下不会污染全局命名空间,除非通过
export显式地暴露给其他模块使用。 - 提供了一种方式来避免全局命名冲突,并有助于更好地组织和封装代码。
- 随着ES6引入模块系统(
- 词法作用域(Lexical Scope)/静态作用域:
- 词法作用域指的是在编写代码时确定的变量和函数的作用域,并且这种作用域关系不会受到运行时的变化影响。
- 子函数会继承父函数的作用域,形成一个链式结构,这个链条被称为“作用域链”。
- 全局作用域(Global Scope) :
4. 作用域链(Scope Chain)
- 定义:由多个作用域组成的链条,用于变量查找。
- 形成方式:函数定义时就已经确定(基于词法作用域),而不是运行时。
- 查找规则:
- 从当前作用域开始查找变量。
- 如果找不到,沿着作用域链向上查找,直到全局作用域为止。
5. GO (Global Object) :
- 含义:JS引擎在代码执行之前,会在
堆内存中创建一个全局上下文全局对象。在浏览器环境中通常是window对象,在Node.js环境中是global对象。 - 作用:提供了一个全局范围内的命名空间,所有全局变量都是全局对象的属性,该对象包含,Date Array String setTimeout等。
6. VO (Variable Object) :
- 含义:变量对象。是一个抽象的概念,用来描述在执行上下文中存储变量、函数声明等的地方。在全局执行上下文中,它对应全局对象(如浏览器中的
window对象);在函数执行上下文中,它就是活动对象(AO)。 - 作用:作为执行上下文的一部分,用于存储变量声明、函数声明等信息。
7. AO (Activation Object) :
- 含义:活动对象。在ES5及之前版本中,当一个函数被执行时,它的执行上下文会创建一个活动对象。这个对象存储了该函数的所有局部变量、命名参数、参数集合以及
this值。 - 作用:用于表示函数调用时的上下文环境。
8. LE (Lexical Environment) :
- 含义:词法环境。自ES6起引入的概念,用于替代传统的VO/AO机制。词法环境包含两部分:环境记录(存储变量/函数声明)和对外部环境的引用(形成作用域链)。
- 作用:定义了变量和函数在何处被存储,并决定了它们的查找方式。
9. VE (Variable Environment) :
- 含义:变量环境。也是自ES6起引入的一个概念,它是词法环境的一部分,专门负责存储当前执行上下文中通过
var声明的变量和其他特定类型的声明(如function)。 - 作用:用于保存当前执行上下文中的变量声明。
10. ER (Environment Record) :
- 含义:环境记录。属于词法环境的一部分,用于实际存储变量、函数声明等信息。
- 作用:具体实现词法环境的功能,保存着当前词法环境中的标识符(变量名、函数名等)到值的映射关系。
上述图解:
2. ES3,JS运行解析
示例1:
相关解析概念:GO / VO / AO / Scope / Scope list
示例2:
相关解析概念:VE / LE / ER / Scope / Scope list
执行前:
执行后:
3. ES6,JS运行解析
ES5/ES6之后的ECMAscript解析示意图:【重要】
4. 相关知识
4.1 闭包(Closure)
是指一个函数能够访问并记住其词法作用域(lexical scope),即使该函数在其作用域外执行。 内部函数引用了外部函数的变量,并且被外部保留下来,就形成了闭包
闭包的主要用途
闭包优点
闭包缺点
4.2 内存泄漏(Memory Leak)
内存泄漏是指程序在运行过程中分配了内存空间,但在不再需要时没有正确释放,导致这部分内存无法被重新利用。随着时间的推移,这可能导致系统性能下降甚至崩溃。
4.3 如何避免闭包导致的内存泄漏?
- 及时解除引用 手动将不再需要的闭包设为
null。 - 使用弱引用结构(如 WeakMap / WeakSet) 适用于缓存或映射对象时,不阻止垃圾回收。
- 避免不必要的全局闭包 尽量减少将闭包暴露到全局作用域。
- 使用工具检测内存泄漏 如 Chrome DevTools 中的 Memory 面板,可以分析内存快照,查找未释放的对象。
4.4 变量提升(Hoisting)
JavaScript引擎在编译阶段,变量和函数声明会被移到其所在作用域的顶部。
变量提升优点
- 灵活性:允许开发者在声明之前使用变量或函数,增加了编写代码的灵活性。
- 初始化函数:有助于定义可以在其他函数或代码块之前调用的初始化函数,方便模块化的代码设计。
变量提升缺点
- 混淆代码:可能导致代码阅读困难,因为变量和函数可以在它们声明之前被访问,容易让人误解代码的逻辑流程。
- 意外覆盖:由于
var声明的变量具有函数作用域而不是块作用域,可能会导致意外的变量覆盖或不正确的值,尤其是在循环或条件语句中。 - 难以调试:错误可能不容易被发现,特别是当变量在作用域的不同部分被重新声明或赋值时。