词法欺骗:eval和with,尽量少用
1.eval
function demo1(str,a){
eval(str)//欺骗
console.log(a,b)
}
var b =2;
demo1("var b=3",1)
eval("var b = 3"),在demo1内部声明了一个b变量,对已经存在的demo1的词法作用域进行了修改,内部创建的b变量遮蔽了全局作用域中同名的b变量。
因此当console.log(a,b)在demo1内部同时找到了a,b所以就不会向外部找了,因此输出1,3
function demo2(){
'use strict'
eval(str)//ReferenceError: str is not defined
console.log(a,b)
}
var b =2;
demo2("var b=3",1)
在严格模式下,eval有自己的词法作用域,因此不会修改修改所在的词法作用域。
类似于eval的还有setTimeout,setInterval。他们的第一个参数都可以是字符串会被解释为一段代码。
with
(1)with方便的访问对象
var obj = {
a:1,
b:2
}
console.log(obj.a)//1
console.log(obj.b)//2
with(obj){
console.log(a)//1
console.log(b)//2
}
(2)with不仅仅有方便访问对象的功能,还可以:
function foo(obj){
with(obj){
a=2//这里其实是一个LHS查询,将2复制给a
}
}
var obj1 = {
a:1
}
var obj2 = {
b:2
}
foo(obj1)
console.log(obj1.a)//2
foo(obj2)
console.log(obj2.a)//undefined
console.log(a) //2
当obj1传进去,a=2找到了obj1.a,将2赋值给它,第二个obj2传进去并未找到obj.a,因此不会创建a这个属性,所以obj2.a为undefined。
但是最后为什么console.log(2)打印出来是2,因为a=2创建了一个全局变量a,并为其赋值为2
with可以将一个没有或有多个属性的对象处理为一个完全隔离的词法作用域,因此这个对象的属性
也会被处理我定义在这个作用域的词法表示符。
注意:尽管with块可以将一个对象处理为词法作用域,但是这个块内部正常的var声明并不会被限制
在这个快的作用域中,而是被添加到with所处的函数作用域中。