理解
1、引擎:负责程序的编译以及执行过程
2、编译器:负责语法分析以及代码生成等工作
3、作用域:收集并维护由所有声明的标识符组成的一系列查询,根据一些严格的规则,确定当前执行的代码对这些标识符的访问权限。
举个栗子
var a = 2;
var a 的处理


a = 2 的处理


如果最终找到了a,引擎会把2赋值给他,否则会抛出一个异常(ReferenceErrror)
小小解释一下关于ReferenceErrror与TypeError
ReferenceErrror和作用域判别失败相关
TypeError是作用域判别成功了,但是对结果的操作是非法的
术语介绍
LHS:赋值操作的左侧
当变量出现在赋值操作的左侧进行LHS查询
试图找到变量容器的本身,从而对其进行赋值
RHS:赋值操作的右侧
(可以理解成‘retrieve his source value’获取到他的原值)
当变量出现在赋值操作的右侧进行RHS查询(非左侧)
得到XXX的值
比如console.log(a)
这就是对a的RHS查询
再考虑一下这个吧!!!
function foo(a) {
console.log(a);
}
foo(2)
有几个LHS和RHS呢?
在非严格模式的LHS查找没有找到,会隐式创建一个引用的目标作为标识符
在作用域进行查找
举个栗子
var a = 3;
// 这是第一个作用域(全局作用域)
function foo(a) {
var c = 5;
// 这是第二个作用域
var b =a * 2;
function bar(c) {
// 这是第三个作用域
console.log(a,b,c);
}
bar(b*3);
}
foo(2);
因为作用域由内向外查找并在第一个匹配的标识符的时候就停止,因此在多层嵌套作用域中可以命名相同的标识符
遮蔽效应就是内部的标识符遮蔽了外部的标识符
全局变量会会自动生成全局对象的属性(比如浏览器中的window对象),所以可以间接的通过对全局都西昂属性的引用来进行访问,比如window.a;
所以全局变量被遮蔽可以用这种方法访问,但是非全局变量被遮蔽,无论如何都没办法被访问到。
欺骗词法
eval()
可以接受一个字符串作为参数,并将字符串中的内容当作在书写时就在程序中这个位置的代码。
举个栗子
function foo(str,a) {
eval(str);
console.log(a,b);
}
var b = 2;// 被遮蔽啦!!!
foo("var b = 3;", 1)
//输出结果:1,3
以上代码相当于:
function foo(a) {
var b = 3;
console.log(a,b);
}
var b = 2;
foo(1)
严格模式下eval有自己的词法作用域,无法修改所在的作用域。
拓展关于setTimeout与setInterval,new Function()
去浏览器试一下吧!!
setTimeout('alert(\'aaaaaaaaaa\')',200)
with
举个栗子
function foo(obj) {
with(obj) {
a = 2;
}
}
var obj1 = {
a: 3
};
var obj2 = {
b: 4
};
foo(obj1);
console.log(obj1.a); // 2
foo(obj2);
console.log(obj2.a); // undefined
console.log(a); // 2
with可以将对象创建一个完全隔离的作用域,所以对象的属性被处理为定义在这个作用域的标识符
如果with块内部正常的var声明不会被限制在他创建的作用域中,而实添加到with所处的作用域中(但是let和const声明会被限制)。
with创建的作用域
