概念赏析:
执行环境(execution context)
有时也可叫做执行上下文,定义了当前环境下可访问的其他数据。执行环境有 全局执行环境 和 函数执行环境(eval执行环境类比函数执行环境)。
变量对象(variable object)
变量对象是与执行上下文对应的概念,上下文中定义的所有成员都保存在这个对象中。
该对象仅供解析器使用,开发者无法访问
活动对象 (activation object)
活动对象是在函数被调用时创建的,最开始时只包含一个变量:arguments 对象。
函数执行环境将其活动对象作为变量对象;
环境栈 (context stack)
每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被压入一个环境栈中。在函数执行之后,栈将其环境弹出(环境被销毁,保存在其中的变量和函数定义也随之销毁;但闭包会改变这一行为),把控制权交还给之前的执行环境。
全局执行环境
在Web浏览器中被认为是window对象(window对象作为变量对象?)。
因此所有全局变量、函数都是作为window对象的属性和方法创建的。全局执行环境是最外围一个执行环境,直到应用关闭才会被销毁
作用域链 (scope chain)
当代码在一个环境中执行时,会创建一个作用域链来指向变量对象,以保证对执行环境有权访问的变量、函数的有序访问。
作用域链的前端始终是当前执行代码所在环境的变量对象,而作用域链中的下一个变量对象来自外部(包含)环境,一直延续到全局执行环境。全局执行环境的 变量对象 始终是作用域链中的最后一个对象
LHS vs RHS
标识符解析是沿着作用域链一级一级地搜索标识符的过程,始终从作用域链的前端开始,逐级向后回溯。查找类型有两种:LHS和RHS。
L 和 R 的含义是 赋值操作的左侧或右侧。
-
当执行LHS查询时,如果找不到目标变量,就会在全局作用域中创建一个具有该名称的变量(非严格模式下,严格模式下同样会抛出 ReferenceError )。
-
如果RHS查询在作用域中找不到所需变量,引擎会抛出 ReferenceError 。
词法作用域
大部分标准语言编译器的第一个工作阶段叫作词法化(也叫单词化)。词法化的过程会对源代码中的字符进行检查,如果是有状态的解析过程,还会赋予单词语义。
作用域共有两种主要的工作模型:
- 词法作用域,被大多数编程语言所采用的。
- 动态作用域,仍有一些编程语言在使用(比如 Bash 脚本、Perl 中的一些模式等)。
JavaScript 中的作用域就是词法作用域。
简单地说,词法作用域就是定义在词法阶段的作用域。也可以理解为,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变(大部分情况下是这样的,eval、with会修改作用域)。
看一下例子:
function foo(){
console.log(a)
}
function bar(){
var a = 3;
foo()
}
var a = 2
bar() // 输出 2
//词法作用域让foo的作用域链前端的下面是全局变量对象。
//如果JS具有动态作用域,那么理论上应该输出3,因为顺着调用栈可以找到bar的作用域。
由此可见,JS作用域链的生成是基于代码中的作用域嵌套,而不是基于栈调用的。
网友评论