eval 的使用

需求

假如有个对象是 { a : { b : 1 }, c: true } ,希望输入字符串 {{a.b}} 得到结果 1;输入 c 得到结果 true

试了 stackoverflow 的写法,代码如下:

function evalInScopeOld(js, contextAsScope) {
    // Return the results of the in-line anonymous function.
    // call with the passed context
    return function() { 
        with(this) { 
            return eval(js);
         }; 
    }.call(contextAsScope);
}

弹出报错Uncaught SyntaxError: Strict mode code may not include a with statement。代码出现 with 就无法执行。

于是参考 vue 的 _render 的写法,代码如下

function evalInScope(js, contextAsScope) {
    let fn = new Function(`with(this){return eval("${js}");}`);
    return fn.call(contextAsScope);
}

可以正常运行。

原因分析如下:

MDN网站的描述:

由 Function 构造器创建的函数不会创建当前环境的闭包,它们总是被创建于全局环境,因此在运行时它们只能访问全局变量和自己的局部变量,不能访问它们被 Function 构造器创建时所在的作用域的变量

js运行的三个阶段:

  1. 简单语法分析阶段:这个阶段还没分析new Function里面的语法,所以fn里面的with不会报错;而fn1里面的with报语法错误

  2. 预编译阶段

  3. 解释执行阶段:new Function的执行发生在解释执行阶段,已经不在简单语法分析阶段

参考链接

[^1] Uncaught SyntaxError: Strict mode code may not include a with statement

[^2] vue的_render函数的with语句为什么不报错 - 简书 (jianshu.com)

最后更新于