浅谈javascript做用域

理解做用域

做用域负责收集并维护由全部声明的变量组成的集合,等待引擎的查找。闭包

var a = 2;
console.log(a);  // 2
console.log(b);  // ReferenceError: b is not defined
  1. var a = 2 能够分解为var a; a = 2。当遇到var a时,编译器会询问做用域是否存在变量a。若是存在,则忽略该声明,不然会在当前做用域的集合中声明一个新的变量a
  2. 遇到a = 2时,引擎会询问当前做用域是否存在变量,若是未找到,则会继续在上级做用域查找。若是最终找到就会将2赋值给变量a
  3. console.log(a)时,引擎会去做用域中查找 a,找到把结果返回,输出2, console.log(b)时,引擎未在做用域查找到b,抛出异常。

LHS和RHS查询

能够看出'L'和'R'分别表明左侧和右侧,即赋值的左侧和右侧。赋值不仅是=的赋值,函数参数的传递也是一种赋值操做。函数

var a = 2;  // LHS查询,a出如今赋值左侧
console.log(a);  // RHS查询, a出如今赋值右侧,将变量a赋值给参数

查询失败会出现什么状况
对于LHS查询a = 2 若a未找到,在非严格模式下并不会报错,而变量 a 会被自动建立。而对于 RHS 来讲,直接使用未声明的变量就会报 ReferenceError。code

console.log(b);  // ReferenceError: b is not defined

词法做用域

做用域主要有两种工做模型:词法做用域和动态做用域。
词法做用域就是定义在词法阶段的做用域。换句话说,词法做用域是由你写代码时变量和块做用域写在哪决定的。ip

function foo(a) {
    var b = a * 2;
    function bar(a) {
        console.log(a, b, c);
    }
    bar(b*3);
}
foo(2);

在这个例子有三个逐级嵌套的做用域。作用域

  1. 全局做用域,包含一个标识符:foo
  2. foo所建立的做用域,包含三个标识符:a, bar, b
  3. bar所建立的做用域,包含一个标识符:c

函数做用域

函数做用域是指属于这个函数的变量均可以在整个函数范围内使用和复用。编译器

function fn() {
    var a = 2;
    console.log(a);  // 2
}

console.log(a); // ReferenceError: a is not defined

从中能够看出,函数外部将没法访问函数内部的变量。it

块做用域

ES6引入letconst将变量绑定到所在块做用域(一般是{...}内部)io

{
    let a = 2;
    console.log(a);  // 2
}
console.log(a);  // ReferenceError: a is not defined

letconst外,withtry/catchcatch分句会建立一个块做用域。console

小结

函数是Javascript中最多见的做用域单元。但函数不是惟一的做用域单元。块做用域属于某个代码块(一般指{...}内部)。
接下来会讲解提高和闭包两个概念。编译

相关文章
相关标签/搜索