You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否扩展JavaScript默认函数原型以在每次函数调用时执行自定义代码?

问题

现有如下函数:

function a(someparams){
 console.log('a called')
}
function b(){
 console.log('b called')
}
...
const c = (someParam) => { console.log('c called')}

我希望在页面代码最开头扩展默认函数原型,比如添加:

Function.prototype.onCall = (args) => {console.log('Proxy fn called!',args)}

让所有已有及新定义的函数在被调用时,都能打印Proxy fn called!,目的是自动校验参数有效性。目前遍历window对象中函数的方案仅对已有函数生效,我想通过扩展原型实现,且不考虑TypeScript或Flow方案。

请问这是否可行?应该从哪方面入手?

我找到了以下方案:

(function() {
    var call = Function.prototype.call;
    Function.prototype.call = function() {
        console.log(this, arguments); // 此处可执行自定义操作
        return call.apply(this, arguments);
    };
}());

但它仅在显式调用.call或.apply时生效,普通调用如someFunction();不会触发。

另外我考虑过装饰器方案,但它尚未成为标准,不过有对应的Babel插件,请问该方案是否可行?还是我找错了方向?


解决方案

一、扩展原型实现全局函数调用拦截的可行性

可行,但要注意:普通函数调用(如fn())不会直接触发Function.prototype.call,而是由JS引擎直接执行函数内部代码,所以你之前修改call方法的方案只能覆盖显式调用call/apply的场景。要拦截所有函数调用,得从修改函数执行的入口逻辑入手。

二、正确的实现方向

1. 重写Function.prototype.constructor拦截新函数创建

通过拦截函数的构造过程,给所有新创建的函数包裹拦截逻辑,同时对已有函数批量包装:

// 保存原生Function构造器
const OriginalFunction = Function;

// 重写Function构造器,拦截新函数创建
Function = function(...args) {
    // 创建原生函数
    const fn = new OriginalFunction(...args);
    // 判断是否为箭头函数(箭头函数无prototype)
    if (!fn.prototype) {
        return (...callArgs) => {
            console.log('Proxy fn called!', callArgs);
            return fn(...callArgs);
        };
    }
    // 包装普通函数
    const wrappedFn = function() {
        console.log('Proxy fn called!', arguments);
        return fn.apply(this, arguments);
    };
    // 标记已包装,避免重复处理
    wrappedFn.__isWrapped__ = true;
    return wrappedFn;
};

// 给已有全局函数批量添加拦截
for (const key in window) {
    const target = window[key];
    if (typeof target === 'function' && !target.__isWrapped__) {
        const originalFn = target;
        window[key] = function() {
            console.log('Proxy fn called!', arguments);
            return originalFn.apply(this, arguments);
        };
        window[key].__isWrapped__ = true;
    }
}

2. 装饰器方案的局限性

装饰器目前处于提案阶段,即便用Babel插件,也只能在编译阶段对函数添加拦截逻辑,无法处理运行时动态创建的函数,也不能自动覆盖页面中已有的函数(除非你能控制所有代码的编译流程)。如果你的代码都是自主编写且能统一编译,装饰器可以用来规范新函数的参数校验,但无法满足“全局自动拦截所有已有和新函数”的核心需求,所以这个方向不符合你的诉求。

三、注意事项

  • 箭头函数的特殊性:箭头函数无prototype且this绑定固定,包装时要避免修改其this指向,用箭头函数的形式包裹即可保留特性。
  • 避免无限递归:包装函数时添加__isWrapped__标记,防止重复包装导致栈溢出。
  • 内置函数限制:部分内置函数(如console.log)依赖引擎内部实现,强行包装可能引发异常,需谨慎处理。

内容的提问来源于stack exchange,提问作者Maria

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 15:50:27