// 定义一个闭包函数,用来创建拦截函数的钩子 function Closure(injectFunction) { // 返回一个新函数,用于处理输入参数并调用原始函数 return function() { // 如果没有传入参数,直接调用原始的 injectFunction if (!arguments.length) return injectFunction.apply(this, arguments); // 获取参数的最后一个值,并替换掉 "debugger" 字符串 arguments[arguments.length - 1] = arguments[arguments.length - 1].replace(/debugger/g, ""); // 调用原始函数并返回结果 return injectFunction.apply(this, arguments); } } // --- 拦截 Function.prototype.constructor --- // 备份原始的 Function 构造器 var oldFunctionConstructor = window.Function.prototype.constructor; // 使用 Closure 包装 Function 构造器,并拦截 debugger window.Function.prototype.constructor = Closure(oldFunctionConstructor); // 为了保持代码一致性,绑定原始的 toString 方法到新构造器 // 这样可以让 toString 方法输出原始代码 window.Function.prototype.constructor.toString = oldFunctionConstructor.toString.bind(oldFunctionConstructor); // --- 拦截 Function --- // 备份原始 Function 对象 var oldFunction = Function; // 替换全局 Function 对象,并拦截 debugger window.Function = Closure(oldFunction); // 同样,为了保持一致性,绑定原始的 toString 方法到新的 Function 对象 window.Function.toString = oldFunction.toString.bind(oldFunction); // --- 拦截 eval --- // 备份原始 eval 函数 var oldEval = eval; // 使用 Closure 包装 eval 函数 window.eval = Closure(oldEval); // 同样绑定原始的 toString 方法,以便 eval.toString() 返回原始代码 window.eval.toString = oldEval.toString.bind(oldEval); // --- 拦截 GeneratorFunction --- // 获取生成器函数的原型构造器(通常为 GeneratorFunction) var oldGeneratorFunctionConstructor = Object.getPrototypeOf(function*() {}).constructor; // 使用 Closure 包装生成器函数构造器 var newGeneratorFunctionConstructor = Closure(oldGeneratorFunctionConstructor); // 绑定原始 toString 方法 newGeneratorFunctionConstructor.toString = oldGeneratorFunctionConstructor.toString.bind(oldGeneratorFunctionConstructor); // 将拦截后的构造器重新定义为 GeneratorFunction 的构造器 Object.defineProperty(oldGeneratorFunctionConstructor.prototype, "constructor", { value: newGeneratorFunctionConstructor, writable: false, // 不允许修改 configurable: true // 允许重新配置 }); // --- 拦截 AsyncFunction --- // 获取异步函数的原型构造器(通常为 AsyncFunction) var oldAsyncFunctionConstructor = Object.getPrototypeOf(async function() {}).constructor; // 使用 Closure 包装异步函数构造器 var newAsyncFunctionConstructor = Closure(oldAsyncFunctionConstructor); // 绑定原始 toString 方法 newAsyncFunctionConstructor.toString = oldAsyncFunctionConstructor.toString.bind(oldAsyncFunctionConstructor); // 将拦截后的构造器重新定义为 AsyncFunction 的构造器 Object.defineProperty(oldAsyncFunctionConstructor.prototype, "constructor", { value: newAsyncFunctionConstructor, writable: false, // 不允许修改 configurable: true // 允许重新配置 });
代码解释和用法
这个代码片段可以作为一个整体直接引入 JavaScript 项目中,用于检测和移除代码中的 debugger
关键字。其核心在于定义 Closure
函数,并利用该闭包创建钩子来拦截多个 JavaScript 构造器。
主要用途
- 移除 debugger:自动去除动态生成的 JavaScript 代码(例如通过
Function
、eval
、GeneratorFunction
、AsyncFunction
创建的代码)中的debugger
关键字,防止调试断点。 - 兼容多种函数类型:覆盖了普通函数、生成器函数和异步函数,确保不同类型的函数构造行为统一。
- 保留原始行为:虽然代码拦截了构造过程,但调用
.toString()
依然返回原始函数的内容,不会影响外部代码逻辑。
如何使用
可以将整个代码片段直接粘贴到 JavaScript 文件中,执行后环境中的 Function
、eval
、GeneratorFunction
和 AsyncFunction
的构造器都会自动去除 debugger
。