第一章 作用域是什么
作用域就是一套方便查找存储变量的规则。
引用变量的时候有两种引用方式:LHS引用和RHS引用。
当变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS引用。LHS引用是试图找到变量的容器本身,从而可以对其赋值。RHS不需要找到变量的容器本身,只需要知道变量的值即可。
console.log(a);
这是一个RHS引用,因为这条语句并不是赋值操作。只是需要查找到a的值,传递给console.log。
a = 2;
这是一个LHS引用,因为我们并不关心a是什么值,只是要把2这个值赋给一个对象。
当我们在当前作用域中无法找到某个变量时,引擎会在外层嵌套的作用域中继续查找,知道找到该变量,或抵达最外层的作用域(全局作用域)为止。
而当引擎执行LHS查询时,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎,前提是程序运行在非“严格模式”下
异常:
如果RHS查询找到了一个变量,但是你尝试对这个变量的值进行不合理的操作,比如试图对一个非函数类型的值进行函数调用,或着引用null或undefined类型的值中的属性,那么引擎会抛出另外一种类型的异常,叫作TypeError。ReferenceError同作用域判别失败相关,而TypeError则代表作用域判别成功了,但是对结果的操作是非法或不合理的。
实例分析:
1.
function test(a){
console.log(a + b);
b = a;
}
test(2);
当执行到console.log(a+b)时,由于b未声明,并且还未执行到b=a这条语句,所以引擎不会自动对b进行全局声明,于是此时会跳出ReferenceError的 异常。
2.
function test(a){
b = 2;
console.log(a + b);
}
console.log("b==="+b);
test(2);
当执行到console.log("b==="+b)时,此时是一个RHS,同时b未声明,引擎会报ReferenceError的异常。
3.
function test(a){
b = 2;
console.log(a + b); /4
}
test(2);
console.log("b==="+b); /b=2
例3和例2的区别是把test(2)和console.log("b==="+b)这两条语句的位置变换了一下,此时引擎上输出 4和b===2。为什么此时又能够顺利执行呢?因为test(2)中,b=2是LHS查询,当程序执行到b=2时,编译器会在当前test函数作用域中查找b的声明,当前作用域中没有b的声明,就跳出当前test函数作用域,跑到全局作用域中查找,还是没有b的声明,就在全局作用域中直接隐性对b进行了全局声明。所以当test(2)执行完成之后,全局作用域中已经有了b的声明,并且在test(2)中对b进行了赋值,b=2。再console.log("b==="+b)的时候,b有值,并且b=2。
4.
function test(a){
var b = 2;
console.log(a + b); /4
}
test(2);
console.log("b==="+b); /ReferenceError
例4和例3的区别在test中var b=2,在test函数作用域中对b进行了声明,此时b的作用域在test函数作用域中,超出test函数作用域的范围,就无法获取到b。所以在全局作用域中console.log("b==="+b)打印b的值的时候,会报ReferenceEror的异常。
posted on 2019-02-02 00:26 atomgame的记事本 阅读(93) 评论(0) 收藏 举报