eval黑魔法失去了范围

时间:2017-06-07 20:25:59

标签: javascript ecmascript-6 eval es6-promise

免责声明 我不支持使用eval,在编写代码时我不会使用它。

我在遗留项目中使用逻辑,并且在eval中遇到了一些非常奇怪的行为,并想知道为什么会出现这种行为的原因。

var baz = function(cb) {
    cb('asdf');
}

function foo(qux, callback) {
    setTimeout(function() {
        // eval(callback('asdf')); // works
        // eval(baz(callback)); // works
        // eval(qux + "(" + callback + ")"); // resolve is undefined
    });
}

function bar() {
    return new Promise((resolve, reject) => {
        try {
            foo('baz', function(response){
                resolve(response);
            });
        } catch (e) {
            reject(e);
        }
    });
}

function init() {
    bar()
    .then(response => {
        console.log(response)
    })
    .catch(e => console.log(e));

}

init();

我写了三个使用eval的不同方法的例子,在函数foo中注释掉了 第三个例子不起作用。这是我关心的例子,因为它是我们遗留代码的工作方式。我知道还有其他方法可以解决这个问题。我的解决方案是重写函数, 完全使用eval。

我的问题非常准确, 为什么 在您将函数名称作为字符串传递时eval会丢失范围,但是当您传入一个字符串时它不会丢失范围实际参考同一个函数?

这是一个jsfiddle: https://jsfiddle.net/tkcjay4x/6/

1 个答案:

答案 0 :(得分:8)

我不得不承认,标题让我有点害怕。如果我理解这个"黑魔法",它会让我成为一个邪恶的巫师吗?

执行eval(baz(callback))时,baz调用callbackeval执行baz的返回值,即undefinedeval(undefined)等于eval('undefined'),等于undefined。因此,在这种情况下,使用eval基本上是无操作 - 只需执行baz(callback)就可以得到相同的结果。

当您执行eval(qux + "(" + callback + ")")时,qux + "(" + callback + ")"评估为'baz(function(response){ resolve(response); })'。当您将其传递给eval时,代码会尝试访问名为resolve的函数,该函数在当前作用域中不存在。这就是为什么它不起作用的原因。如果直接调用函数,它可以访问定义它的作用域中的变量,但是如果将函数转换为字符串并将其传递给eval,它只能访问当前作用域中的变量