js eval - msforest/notebook GitHub Wiki

从入门以来,大家就一直说不要使用 eval 这邪恶的东西,然后我就信了(后面就没有去认真了解它),还是太年轻了;殊不知,这东西是非常好的东西,今天就来聊聊这“可恶”的东东;知己知彼,方能为我所用。

首先来了解一下,大家为啥这么反感 eval;

  • eval 作用域不明确
  • eval 接受并执行所传入的字符串,导致运行未知的代码,更重要的是,所传入的代码可以通过 eval 运行其他的脚本,导致受到攻击

参数

eval 只会对字符串进行解析执行并返回执行的结果,如果传入的参数不是字符串,那么不会做任何处理,原样返回; 例如:

var a1 = [1, 2, 3, 4];
var a2 = eval(a1); // non-string
a1 === a2;

var a3 = "2**3";
var a4 = eval(a3); // string
a4 === 8;

作用域

如果是直接调用 eval,作用域为 local;如果是间接调用,作用域为 global; 例如:

function test() {
  var x = 2,
    y = 4;
  console.log(eval("x + y")); // Direct call, uses local scope, result is 6
  var geval = eval; // equivalent to calling eval in the global scope
  console.log(geval("x + y")); // Indirect call, uses global scope, throws ReferenceError because `x` is undefined
  (0, eval)("x + y"); // another example of Indirect call
}

我还记得入门时对 eval 的使用仅限于解析 json 字符串转成对象,一定要加括号,不加就会报错;和JSON.parse解析报错的信息不一样;至今才知道,var obj = {a: 1}转换成字符串是这样"{"a": 1}";然后 eval 解析字符串时,会把字符串当做执行语句,当解析大括号({)时会被当做语句块;执行冒号(:)时就遇到语法错误。这和正常写代码{"a": 1}这样也会报错,要想解析成对象,需要加括号来表示里面不是一个语句块;

var obj = { a: 1 };
var str = JSON.stringify(obj);

eval("(" + str + ")") === { a: 1 };
// 等同于
JSON.parse(str);