作用域和闭包

作用域和闭包

LHS和RHS

LHS查询是试图找到变量的容器本身,然后对其赋值

RHS查询是简单地查找某个变量的值

在变量还没有声明(在任何作用域中都无法找到该变量)的情况下:

  • RHS查询所有嵌套的作用域中都找不到对应的变量,则会抛出ReferenceError
  • LHS查询,如果在最顶层(全局作用域)中都无法找到该变量,则会在全局作用域中创建一个具有该名称的变量(程序运行在非严格模式下);如果是在严格模式下,则会抛出和RHS类似的异常

作用域查找

作用域查找会在找到第一个匹配的标识符时停止,同时始终从运行时所处的最内部作用域开始,逐级向外或向上进行,直到遇到第一个匹配的标识符

词法作用域查找只会查找一级标识符,如果代码中引用了foo.bar.baz,词法作用域只会试图查找foo标识符,找到这个变量后,对象属性访问规则会接管对bar和baz属性的访问

欺骗词法

JavaScript提供了两种机制来实现:运行时修改词法作用域

eval

接受一个字节串为参数,并将其中的内容视为好像在书写时就存在于程序这个位置的代码

1
2
3
4
5
6
function foo(str, a) {
eval(str)
console.log(a, b)
}
var b = 2
foo('var b = 3', 1) // 1, 3

严格模式下,eval在运行时有其自己的词法作用域,里面的声明无法修改所在的作用域

with

with通常被当作重复引用同一个对象中多个属性的快捷方式,可以不需要重复引用对象本身。本质是将一个对象的引用当作作用域来处理,将对象的属性当作作用域中的标识符,从而创建了一个新的词法作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj = {
a: 1,
b: 2,
c: 3
}
obj.a = 2
obj.b = 3
obj.c = 4

// 快捷方式
with(obj) {
a = 2
b = 3
c = 4
}

性能

JavaScript引擎会在编译阶段进行数项的性能优化。其中有些优化依赖于能够根据代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符。但如果代码中存在eval和with,则只能简单地假设关于标识符位置地判断都是无效的,因为无法在词法阶段分析明确知道eval会接收到什么代码,这些代码会如何修改作用域


作用域和闭包
http://xrcol.github.io/2023/05/14/fd1c98a2ecdf/
作者
XR
发布于
2023年5月14日
许可协议