词法作用域就是在书写代码时产生的作用域,是由你将变量和块作用域写在哪里来决定的。

1
2
3
4
5
6
7
8
function foo (a) {
var b=a*2;
function bar(c){
console.log(a,b,c);
}
bar(b*3);
}
foo(2);//2,4,12

作用域有三块
1.包含着bar创建的作用域,标识符是c
2.包含foo创建的作用域,标识符是a bar b
3.全局,标识符foo
逐级嵌套的

修改词法作用域还有一个叫“欺骗”
两种机制:eval和with

eval(…)

1
2
3
4
5
6
function foo(str,a){
eval(str);
console.log(a,b);
}
var b=2;
foo("var b=3",1);//1,3

eval内的代码引擎不知道他是以动态形式插入的,所以可以修改原来的词法作用域

with

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function foo(obj){
with(obj){
a=2;
}
}
var o1={
a:3
};
var o2={
b:3
}
foo(o1);
console.log(o1.a);//2
foo(o2);
console.log(o2.a);//undefined
console.log(a);//2

O1中有定义a,o2中没有
with的本质是通过把一个对象的引用当做作用域来处理

不推荐使用的原因:

1.严格模式下with被完全禁止,eval(…)间接和非安全的使用也被禁止
2.性能差,因为引擎发现了eval和with后只能简单的假设关于标识符位置的判断都是无效的,也无法在此法分析阶段知道eval(…)会接收到什么代码,所以优化可能都是无意义的。