作用域以及 LHS 和 RHS 查询

Author Avatar
Roojay 9月 16, 2017
  • 在其它设备中阅读本文章

作用域

1. 作用域是一套规则,负责收集并维护由所有声明的标识符(变量)组成的一系列查询,用于确定在何处以及如何查找变量(标识符),并实施一套非常严格的规则,用于确定当前执行的代码对这些标识符的访问权限。作用域就是函数或者变量能被访问到的范围。

2. 作用域有两种工作模型:

  • 词法作用域(JavaScript):词法作用域就是定义在词法阶段的作用域。
  • 动态作用域(Bash脚本)

3. 全局变量会自动成为全局对象(比如浏览器中的 window 对象)的属性,因此可以不直接通过全局对象的词法名称,而是间接地通过对全局对象属性的引用来对其进行访问。例如:window.a

这样可以访问到被局部同名变量所遮蔽的全局变量。

执行上下文

执行上下文在运行时确定,词法作用域在定义时确定。

欺骗作用域

无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定。

JavaScript 中有两个机制可以“欺骗”词法作用域:eval(..) 和 with。前者可以对一段包含一个或多个声明的“代码”字符串进行演算,并借此来修改已经存在的词法作用域(在
运行时)。后者本质上是通过将一个对象的引用当作作用域来处理,将对象的属性当作作
用域中的标识符来处理,从而创建了一个新的词法作用域(同样是在运行时)。

eval()函数欺骗

JavaScript 中的 eval() 函数可以接受一个字符串为参数,并将传入的字符串视为好像在书写时就存在于程序中这个位置的 JavaScript 代码进行执行。例如:

var a = 66;
function bar(str, b) {
    eval(str);
    console.log(a, b); // 55 10
}

bar('var a = 55;', 10);

使用 eval() 函数可以将代码以动态形式插入一个指定位置,如果 eval() 中所执行的代码包含一个或多个声明(函数或者变量),就会对词法作用域的环境进行修改,达到欺诈伪装的效果。

在严格模式下,eval() 函数拥有这自己的词法作用域,其中的声明将无法修改作用域。

这个函数的副作用是引擎无法在编译时对作用域查找进行优化,会导致代码运行变慢,不建议使用。

LHS 和 RHS查询

LHS 查询

对变量进行赋值操作,那么就会使用 LHS 查询。

当引擎执行 LHS 查询时,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎。

严格模式禁止自动或隐式地创建全局变量。 LHS 查询失败时,并不会创建并返回一个全局变量,引擎会抛出同 RHS 查询失败时类似的 ReferenceError 异常。

RHS 查询

查找获取某个变量的值,就会使用 RHS 查询。

如果 RHS 查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出 ReferenceError 异常。

The MIT License (MIT)
Copyright (c) 2019, Roojay.

本文链接:https://roojay.com/pages/b917f198/