一、彻底理解作用域

学完这一章最大的感触就是可以弄懂一些平时一直在遇到但是或许并不清楚原理的知识点,比如下面两个问题,你清楚原理吗?

Q1:你知道为什么在一个作用域内不使用var声明的变量会变成全局变量吗?

Q2:你知道报错信息referenceErrorTypeError有什么区别吗?它们分别在什么情况下会产生?

《你不知道的javascript》(上卷)中对于作用域的定义是:

作用域是根据名称查找变量的一套规则。

而我在《javascript高级程序设计》一书中写的笔记是:

作用域是变量和函数的可访问范围。

我认为这两者并不矛盾,作用域是一套规则,因为这套规则,所以确定了变量和函数的可访问范围。

首先理解一下变量赋值(eg:var a = 2)会执行的两个操作:

  • 编译器在当前作用域中声明一个变量(如果之前没有声明过)
  • 运行时引擎会在作用域中查找该变量,如果能找到就会对它赋值。

其中引擎在作用域中查找该变量的时候有两种查询方式:LHSRHS

LHS查询
当变量出现在赋值操作符的左边的时候会执行LHS查询,例如a=2,对于a的查询就是LHS查询
换句话说,如果查找的目的是对变量进行赋值,那么就会使用LHS查询。

RHS查询
当变量出现在赋值操作符的右边(严格来说是非左边)时会执行RHS查询,例如console.log(a),这里我们需要查询到a的值,但a的值并没有在操作符的左侧,所以我们对变量a执行的是RHS查询
换句话说,如果查找的目的是获取变量的值,就会使用RHS查询

下面用一个题目来考察是否理解清楚了LHSRHS查询:(题目来自《你不知道的javascript》(上卷))

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

提示:LHS查询有3处,RHS查询有4处噢

答案:
c=foo(2);对c进行LHS查询
a=2(隐式变量分配);对aLHS查询
b=a;对b进行LHS查询

foo(2);对foo进行RHS查询
b=a;对a进行RHS查询
a+b;对ab都进行RHS查询(因为查询的目的是获取ab的值)

你答对了吗?

弄清楚LHSRHS我们可以开始讨论Q1Q2了:

如果RHS查询在所有嵌套作用域中查询不到所需要的变量,就会抛出referenceError的异常,如果RHS查询找到了一个变量,但是试图对这个变量做不合理或者非法的操作,就会抛出TypeError的异常。

LHS查询在所有嵌套作用域查询不到所需要的变量,就会在全局作用域中创建一个具有该名称的变量,并将其返还给引擎(非严格模式下),严格模式下也会抛出一个类似的referenceError错误。所以在一个局部作用域中不用var声明变量的时候,语法就类似于a=2,此时引擎对变量a的查询是LHS查询,所以在非严格模式下会在全局变量中以该名称创建一个变量。

你可能感兴趣的:(一、彻底理解作用域)