您现在的位置:首页 >> 前端 >> 内容

词法作用域之欺骗词法

时间:2017/9/12 9:32:00 点击:

  核心提示:如果词法作用域完全由写代码期间函数所声明的位置来定义,怎样才能在运行时来修改(欺骗)词法作用域。有两种机制来实现这个目的,但最好不要使用,欺骗词法作用域会导致性能下降。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()也被禁止了。

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

作者:网络 来源:Mybells