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

总结

 
  1. Function() 构造函数通过字符串参数动态创建函数,最后一个参数是函数体,前面的是形参。
  2. 核心特点是不继承当前作用域,仅访问全局,这是和普通函数最关键的区别。
  3. 适合动态生成函数的场景,但因性能和安全问题,日常开发中优先使用函数声明(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);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2026-01-25 11:36  chenlight  阅读(1)  评论(0)    收藏  举报