你不知道的 JavaScript 第一章:作用域是什么?

33 阅读2分钟

本文学习目标:

  • 作用域是什么?
  • LHS 和 RHS 是什么?

1.1 编译原理

编译语言和解释语言的区别,可以自行了解。

js 常被归为解释语言,但本质是编译语言,只是编译过程非常短暂(通常在执行前几微秒完成)。

js引擎对编译的步骤和传统步骤非常相似,在传统编译语言的流程中,程序源码在执行前经历三个步骤,统称为编译:

image.png 补充:

1.分词(Tokenizing)是无状态的机械切割,不关心上下文(比如会把I'm拆成I'm);

2.词法分析(Lexing)是有状态的智能解析,会根据上下文合并字符(比如识别I'm是完整的标识符,===是全等运算符而非三个=)。

1.2 作用域的本质:变量查找的“规则手册”

理解作用域,还需要知道引擎和编译器

  • 引擎:负责整个 JavaScript 程序的编译与执行,是 “总指挥”;
  • 编译器:负责分词、解析、代码生成,在编译阶段处理变量声明;
  • 作用域:负责收集所有变量声明,维护变量查询规则,是 “变量管理员”。

自行阅读......

LHS : 引擎问作用域,是否有这个变量,没有向外层作用域询问,一直到最外层作用域,非严格模式下,创造一个全局变量,严格模式下抛出EeferenceError

RHS: 若在所有作用域中都找不到目标变量,引擎抛出ReferenceError(引用错误)—— 表示 “变量未声明”。

难点解析:

image.png 核心原因在于函数声明的编译与执行机制,和普通变量的 “声明→赋值” 流程存在本质差异

var foo = function(a) {},

编译期:处理var foo 声明;

执行期:处理 foo = function 的赋值,需要LHS 查询。

function foo(a) 编译期: 在当前作用域声明 foo 变量(同普通变量的声明逻辑); 直接将函数体对应的 “函数对象” 绑定到 foo 变量上(而非像普通变量那样留到执行期赋值)。这意味着,编译完成后,foo 已经是一个 “有具体值的函数变量”,而非 “空容器”。