插件窝 干货文章 Object.defineProperty和Proxy结合使用时,apply方法为何会被调用两次?

Object.defineProperty和Proxy结合使用时,apply方法为何会被调用两次?

函数 调用 代理 apply 651    来源:    2025-03-19

在使用 Object.definePropertyProxy 结合时,apply 方法被调用两次的原因通常与代理对象的调用方式有关。具体来说,这种情况通常发生在以下场景中:

1. 代理函数的调用

  • 当你使用 Proxy 代理一个函数时,apply 陷阱会在每次函数调用时被触发。
  • 如果你在 Object.defineProperty 中定义了某个属性的 gettersetter,并且这个属性的值是一个函数,那么当你访问这个属性时,getter 会被调用,返回的函数会被代理。

2. 双重调用

  • 当你访问这个属性时,getter 会被触发,返回的函数会被代理。
  • 当你调用这个函数时,Proxyapply 陷阱会被触发一次。
  • 如果 getter 返回的函数本身也是一个代理函数,那么 apply 陷阱可能会被触发两次:一次是代理函数的调用,另一次是原始函数的调用。

示例代码

const targetFunction = function() {
    console.log('Original function called');
};

const handler = {
    apply: function(target, thisArg, argumentsList) {
        console.log('Proxy apply trap called');
        return Reflect.apply(target, thisArg, argumentsList);
    }
};

const proxyFunction = new Proxy(targetFunction, handler);

const obj = {};
Object.defineProperty(obj, 'method', {
    get: function() {
        console.log('Getter called');
        return proxyFunction;
    }
});

obj.method(); // 调用代理函数

输出结果

Getter called
Proxy apply trap called
Original function called

解释

  1. Getter called: 当你访问 obj.method 时,getter 被调用,返回 proxyFunction
  2. Proxy apply trap called: 当你调用 obj.method() 时,Proxyapply 陷阱被触发。
  3. Original function called: Proxyapply 陷阱调用原始函数 targetFunction

为什么 apply 会被调用两次?

  • 如果你在 getter 中返回的函数本身也是一个代理函数,那么 apply 陷阱可能会被触发两次:一次是代理函数的调用,另一次是原始函数的调用。
  • 这种情况通常发生在你嵌套使用 Proxy 或者在 getter 中返回了一个代理函数。

解决方法

  • 如果你不希望 apply 被调用两次,确保 getter 返回的函数不是代理函数,或者避免在 getter 中返回代理函数。

总结

apply 方法被调用两次的原因通常是由于 getter 返回了一个代理函数,导致在函数调用时 Proxyapply 陷阱被触发两次。通过避免在 getter 中返回代理函数,可以解决这个问题。