new Function(推荐)
// 无参数
const code = "return 1 + 2";
const fn = new Function(code);
console.log(fn()); // 3
// 带参数
const fn2 = new Function("a", "b", "return a + b");
console.log(fn2(1, 2)); // 3
// 多行代码
const fn3 = new Function(`
const x = 10;
return x * 2;
`);
console.log(fn3()); // 20
和 eval 的主要区别:
- 有独立函数作用域,不会污染外部变量
- 可以明确传入参数,接口更清晰
- 不能访问外部局部变量(只能访问全局)
eval(不推荐)
const result = eval("1 + 2");
console.log(result); // 3
问题:
- 和外部作用域共享变量,容易出现意外副作用
- 引擎无法优化,性能差
- 各种代码规范和 CSP 都禁止使用
异步代码执行
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
const code = `
const res = await Promise.resolve(123);
return res;
`;
const fn = new AsyncFunction(code);
fn().then(console.log); // 123
Node.js vm 模块(沙箱执行)
适合在 Node 服务端执行用户提交的代码,比 eval 更安全:
const vm = require("vm");
const context = { a: 1, b: 2 };
vm.createContext(context);
const result = vm.runInContext("a + b", context);
console.log(result); // 3
设置超时防止死循环:
try {
vm.runInContext("while(true){}", context, { timeout: 1000 });
} catch (e) {
console.error("超时:", e.message); // Script execution timed out
}
执行来自数据库的函数字符串:
const str = `
function check(order) {
return order.amount > 100;
}
`;
const check = new Function(`${str}; return check;`)();
console.log(check({ amount: 200 })); // true
实战:规则引擎表达式
带上下文变量执行表达式:
function runExpression(expr, data) {
return new Function(
"data",
`with(data){ return ${expr} }`
)(data);
}
runExpression("price * count", { price: 10, count: 2 }); // 20
微信小程序:eval 和 Function 均被禁用
小程序运行环境为了安全禁止动态代码生成:
eval("1+1"); // eval is not a function
new Function("return 1"); // Function constructor is disabled
替代方案一:JSON 规则引擎
{
"op": "and",
"rules": [
{ "field": "amount", "operator": ">", "value": 100 },
{ "field": "vip", "operator": "=", "value": true }
]
}
function runRule(rule, data) {
return rule.rules.every(item => {
switch (item.operator) {
case ">": return data[item.field] > item.value;
case "=": return data[item.field] === item.value;
}
});
}
替代方案二:globalThis 注册函数表
// 初始化时注册所有可调用函数
globalThis.actions = {
checkVip(data) { return data.vip; },
checkAmount(data) { return data.amount > 100; }
};
// 运行时按名称调用
function dispatch(funcName, data) {
return globalThis.actions[funcName]?.(data);
}
dispatch("checkAmount", { amount: 200 }); // true
globalThis 在小程序中可用(等价于浏览器的 window),但 window、document 在小程序里不存在。这种函数表模式是小程序低代码/规则引擎的常见做法。
