JavaScript 中 Function() 构造函数的具体用法
JavaScript 中
Function() 构造函数的具体用法,这是一种动态创建函数的方式,和我们常用的函数声明 / 表达式写法有所不同。一、Function() 构造函数的基础用法
Function() 是 JavaScript 内置的构造函数,用于动态创建函数。它接收的最后一个参数是函数体(字符串形式),前面的所有参数都是函数的形参(同样是字符串形式)。1. 基本语法
// 语法:new Function([arg1[, arg2[, ...argN]],] functionBody)
// 注意:new 关键字可选,不加也能创建函数
const func = new Function(参数1, 参数2, ..., 函数体字符串);
2. 简单示例
// 示例1:无参数的函数
const sayHello = new Function('console.log("Hello, JavaScript!");');
sayHello(); // 输出:Hello, JavaScript!
// 示例2:带参数的函数
const add = new Function('a', 'b', 'return a + b;');
console.log(add(2, 3)); // 输出:5
// 示例3:多个参数也可以用逗号分隔成一个字符串
const multiply = new Function('x, y', 'return x * y;');
console.log(multiply(4, 5)); // 输出:20
二、关键特性与注意事项
1. 作用域问题(核心区别)
Function() 创建的函数不继承当前作用域,而是始终继承全局作用域(严格模式下也如此),这是它和普通函数最大的区别:const num = 10; // 局部作用域变量(在全局中定义,仅作示例)
// 普通函数:能访问外部变量
function normalFunc() {
console.log(num);
}
normalFunc(); // 输出:10
// Function() 创建的函数:无法访问外部变量,只能访问全局
const funcByConstructor = new Function('console.log(num);');
funcByConstructor(); // 报错:num is not defined
// 解决:只有全局变量能被访问
window.num = 10; // 挂载到全局
funcByConstructor(); // 输出:10
2. 动态性(主要使用场景)
适合需要运行时动态生成函数逻辑的场景(比如根据用户输入 / 配置生成函数):
// 动态生成计算函数
function createCalculator(operator) {
let body;
switch (operator) {
case '+':
body = 'return a + b;';
break;
case '-':
body = 'return a - b;';
break;
default:
body = 'return 0;';
}
return new Function('a', 'b', body);
}
const addFunc = createCalculator('+');
console.log(addFunc(10, 20)); // 输出:30
const minusFunc = createCalculator('-');
console.log(minusFunc(20, 10)); // 输出:10
总结
Function()构造函数通过字符串参数动态创建函数,最后一个参数是函数体,前面的是形参。- 核心特点是不继承当前作用域,仅访问全局,这是和普通函数最关键的区别。
- 适合动态生成函数的场景,但因性能和安全问题,日常开发中优先使用函数声明(
function fn() {})或函数表达式(const fn = () => {})。
三、关于Function.prototype.constructor("debugger;")的具体实例分析
Function.prototype.constructor("debugger") 本质上是 Function() 构造函数的一种间接调用方式,核心作用是动态创建一个执行 debugger 语句的函数。
一、先理清核心关系
首先要明确:
Function.prototype.constructor指向的就是Function构造函数本身(Function === Function.prototype.constructor)。- 所以
Function.prototype.constructor("debugger")等价于new Function("debugger")(也等价于Function("debugger"),因为Function构造函数的new关键字可选)。
验证这个关系的代码:
console.log(Function.prototype.constructor === Function); // 输出:true
// 两种写法完全等价
const func1 = Function.prototype.constructor("debugger");
const func2 = new Function("debugger");
console.log(func1.toString()); // 输出:function anonymous() { debugger; }
console.log(func2.toString()); // 输出:function anonymous() { debugger; }
二、Function.prototype.constructor("debugger") 的执行逻辑
1. 基础执行效果
这个写法会创建一个匿名函数,函数体只有
debugger 语句;调用这个函数时,浏览器 / 调试器会触发断点,暂停代码执行:// 创建执行debugger的函数
const debugFunc = Function.prototype.constructor("debugger");
console.log("执行前");
debugFunc(); // 执行到这里,浏览器调试器会暂停
console.log("执行后"); // 只有手动恢复执行,才会打印这行
2. 带参数的扩展写法
如果需要更复杂的逻辑,也可以传参数(和
Function 构造函数规则一致,最后一个参数是函数体):// 等价于 new Function('msg', 'debugger; console.log(msg);')
const debugWithLog = Function.prototype.constructor("msg", "debugger; console.log(msg);");
debugWithLog("触发断点并打印");
// 执行结果:调试器暂停 → 恢复后打印 "触发断点并打印"
三、这个写法的常见使用场景(正反两面)
1. 合法调试场景
开发中偶尔用于动态触发断点,比如在不确定代码执行位置时,动态插入调试逻辑:
// 模拟:根据条件动态添加调试
function runCode(needDebug) {
if (needDebug) {
// 动态执行debugger,不污染原代码
Function.prototype.constructor("debugger")();
}
console.log("业务逻辑执行");
}
runCode(true); // 触发断点
runCode(false); // 正常执行
2. 恶意 / 反调试场景(重点提醒)
这个写法更常见于前端反调试 / 混淆代码中:
- 攻击者会循环执行
Function.prototype.constructor("debugger")(),导致调试器不断暂停,无法调试代码; - 示例(反调试代码):
// 反调试:检测到调试器就无限触发断点
setInterval(() => {
try {
Function.prototype.constructor("debugger")();
} catch (e) {
// 捕获异常,不影响代码运行
}
}, 100);

浙公网安备 33010602011771号