红宝书-了解什么是作用域链增强?

48 阅读2分钟

红宝书原文

某些语句会导致在作用域链前端临时添加一个上下文,这个上下文在代码执行后会被删除。 两种情况会出现这个现象: 1、try/catch语句的catch块 2、with语句

  • try/catch语句的catch块:会创建一个新的变量对象,这个变量对象会包含要抛出的错误对象的声明。
  • with语句:会向作用域链前端添加指定的对象。

前置知识

  1. 作用域链:决定了各级上下文中的代码在访问变量和函数时的顺序。代码正在执行的上下文的变量对象始终位于作用域链的最前端。
  2. 在代码预解析阶段,在每一个作用域中(全局作用域/函数作用域),会确定该作用域的作用域链。
  3. 在代码执行阶段,执行上下文会依次被推入进执行栈中,当一个函数上下文执行完毕之后,会被推出执行栈。

情况一:with语句

function buildUrl(){
  let qs="?debug=true"
  with(location){
    let url=href+qs
    return url
  }
}

console.log(buildUrl()) //https://code.devrank.cn/preview?projectId=7391306329702793253?debug=true

在以上代码块中,with()中的变量location是全局变量,应该放在全局上下文中,当使用到location这个变量时,应该是一直沿着作用域链往外检索,直到检索到全局作用域时,直到这个变量,并使用。但由于使用了with语句,会进行作用域链增强,因此location会被添加到作用域链最前端,如图所示:

image.png

在开发中我们应该尽量减少with语句的使用

因为with语句会使作用域链被加长,除了被添加到最前端的变量外,其他变量标识符解析的性能都会变差!