做用域那点事

做用域

用来声明,访问和修改变量的上下文,定义了变量的访问权限和查找机制。javascript

做用域分类:java

  • 全局做用域 (整个JS运行环境,最顶层做用域,其声明的函数、变量等都是全局的)
  • 函数做用域 (函数执行时会建立做用域)
  • 块级做用域 ({ }大括号在 let、const关键字特性产生的做用域)

JS属于编译语言,逐行执行;编译的过程分为三部分:函数

  • 分词/词法分析。
  • 解析/把词法分析转换成AST(抽象语法树)。
  • 代码生成/把AST转成可执行代码。

示例:code

var a = 1;

编译过程:ip

  • 分红var a、a=1;两部分进行分析。
  • 查看当前做用域是否有a,若是有就忽略,若是没有就建立变量a。
    (var、function声明的变量会在当前做用域下进行变量提高)
  • 赋值操做,首先查看当前做用域下是否有变量a,要是不存在变量a就会报错,要是存在进行赋值;其次若是是做用域嵌套的状况,当前做用域下不存在变量a,就会向外层做用域查找,直到全局做用域,若是不存在变量a就会报错。

执行过程:作用域

  • 执行var a语句进行查找a变量,这个过程叫作LHS(左侧为查找目标)。
  • 执行a = 1赋值操做,过程叫作RHS(右侧为目标查找的目的)。
  • 进行RHS必然会进行LHS。

注意:取值和赋值都是RHS,变量声明和形参是LHS;RHS和LHS发生在执行过程当中。io

示例:编译

function foo(a) {
    var b = a;
    return a + b
}
var c = foo(2)

3处LHS查询:function

  • var c 声明
  • var b 声明
  • 形参 a 声明

4处RHS查询:class

  • foo(2) 取值foo并执行
  • var b = a语句,取值a
  • a + b语句,取值a
  • a + b语句,取值b

做用域嵌套:

当一个块或函数嵌套在另外一个块或函数里,就发生了做用域嵌套。

做用域嵌套下变量的查找规则:

查找变量时若是当前做用域里没有找到,就会向外层做用域查找,直到找到该变量或到全局做用域为止,若是没找到就会报错。

做用域嵌套查找变量的特色:

从内往外,LHS和RHS都会在当前做用域进行,LHS只有当前做用域下没有找到所需变量,才会向外层做用域查找。

变量提高对LHS的影响:

  • 变量提高发生在编译过程,一个没有用var声明的变量不会进行变量提高,在该变量以前进行RHS,会报ReferenceError异常is not defined。
  • 用var声明的变量会进行变量提高,提高到当前做用域的最顶部,其值是undefined,所以在变量前进行取值不会报错。
  • 非严格模式下对没有用var关键字声明的变量语句以前进行RHS,报ReferenceError异常。若是是以后进行RHS,会先进行LHS,若是当前做用域仍是全局做用域下都没有找到,会自动建立一个全局变量并返回,严格模式下LHR查询失败时,并不会建立一个全局变量并返回,报ReferenceError异常。

变量的访问权限问题:

  • 块级做用域里的变量外层做用域是没法访问,变量是指由let,const。
  • 函数的形参和变量,内部函数是外层做用域没法访问,属于局部变量。变量是指由let,const,var,function声明的。

部分参考:

《你不知道的JavaScript》

相关文章
相关标签/搜索