词法作用域之欺骗词法

来源:互联网 发布:催收数据安全管理制度 编辑:程序博客网 时间:2024/04/30 06:51

如果词法作用域完全由写代码期间函数所声明的位置来定义,怎样才能在运行时来“修改”(欺骗)词法作用域。

有两种机制来实现这个目的,但最好不要使用,欺骗词法作用域会导致性能下降。

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);//2foo(o2);console.log(o2.a);//undefinedconsole.log(a);//2---a被泄漏到全局作用域上了

当传o1给with时,with所声明的作用域是o1,而这个作用域中含有一个同o1.a属性相符的标识符。当o2作为作用域时,其中并没有a标识符,因此进行了正常的LHS标识符查找,依次是o2作用域、foo()作用域和全局作用域中都没有找到标识符a,所以当a=2执行时,自动创建了一个全局变量(非严格模式)。如果在foo()作用域中找到了a,就会改变foo()作用域中a的值。

严格模式下with被完全禁止,而保留核心功能的前提下,间接或非安全的使用eval()也被禁止了。

使用其中任何一个机制都将导致代码运行变慢。不要使用它们。

原创粉丝点击