核心提示:如果词法作用域完全由写代码期间函数所声明的位置来定义,怎样才能在运行时来修改(欺骗)词法作用域。有两种机制来实现这个目的,但最好不要使用,欺骗词法作用域会导致性能下降。1. evaleval函数可以接...
如果词法作用域完全由写代码期间函数所声明的位置来定义,怎样才能在运行时来“修改”(欺骗)词法作用域。
有两种机制来实现这个目的,但最好不要使用,欺骗词法作用域会导致性能下降。
1. eval
eval函数可以接受一个字符串为参数,并将其中的内容视为好像在书写时就存在于程序中这个位置的代码。
function foo(str,a){ eval(str);//欺骗 console.log(a,b); } var b=2; foo("var b=3;",1);//1,3
在严格模式的程序中,eval()在运行时有其自己的词法作用域,意味着其中的声明无法修改所在的作用域。
function foo(str){ "use strict"; eval(str); console.log(a);//ReferenceError:a is not defined } foo("var a=2;");
2. with
with通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。
var obj={ a:1, b:2, c:3 } //单调乏味的重复 obj.a=2; obj.b=3; obj.c=4; //简单的快捷方式 with(obj){ a=3; b=4; c=5; d=6;//obj中无d,所以在全局作用域上创建d=6. }
但实际上这不仅仅是为了方便的访问对象属性。
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---a被泄漏到全局作用域上了
当传o1给with时,with所声明的作用域是o1,而这个作用域中含有一个同o1.a属性相符的标识符。当o2作为作用域时,其中并没有a标识符,因此进行了正常的LHS标识符查找,依次是o2作用域、foo()作用域和全局作用域中都没有找到标识符a,所以当a=2执行时,自动创建了一个全局变量(非严格模式)。如果在foo()作用域中找到了a,就会改变foo()作用域中a的值。
严格模式下with被完全禁止,而保留核心功能的前提下,间接或非安全的使用eval()也被禁止了。
使用其中任何一个机制都将导致代码运行变慢。不要使用它们。