在 Node.js 上使用 Proxy.apply() 不起作用。这是一个错误还是我做错了?

Joc*_*oel 7 javascript proxy call apply node.js

我正在使用代理来代理一个对象。getter 和 setter 可以正常工作。但是,从不调用 apply 方法。

    var p = new Proxy({}, {
    /* getter */
    get(target, name) {
        return target[name]
    },
    /* setter */
    set(target, name, value) {
        target[name] = value
    }, 
    /* supposedly called apply */
    apply(target,that,arg) {
        console.log('apply is called, what to do here?')        
    }
})
Run Code Online (Sandbox Code Playgroud)

这样,p即使它不存在,我也可以分配或返回一些东西。例如,当我让 getter 函数返回这个时

get(target, name) {
    return 'getting ' + name
},
Run Code Online (Sandbox Code Playgroud)

然后即使它不存在,console.log(p.flappy)我也会得到“变得飘逸”的响应。

到目前为止一切顺利,但是当我尝试调用flappy 时,p.flapppy()它会抛出一个错误,即flappy 不是函数。

这仍然有些明显,因为 getter 不返回函数。当我让 getter 返回这样的函数时

get(target, name) {
    return function() { return 'this is '+name } 
},
Run Code Online (Sandbox Code Playgroud)

我可以调用该属性而无需它存在。

console.log(
    p.flappy() // this is flappy!
)
Run Code Online (Sandbox Code Playgroud)

那么什么时候申请会被调用?不在我刚刚在这里展示的片段中,也不是在这种情况下:

p.foo = function() {
    console.log('yay!')
    return 'foo!'
}
Run Code Online (Sandbox Code Playgroud)

执行p.foo()or 或p.foo.call()or不起作用p.foo.apply(),在这两种情况下都不会调用 apply 。

这个旅程的最终目的是我想根据属性是被读取还是被调用来返回一个不同的值。像这样:

   p.someNewProperty // return what the getter function returns

    p.anotherProperty() // return something else here because this is a function call
Run Code Online (Sandbox Code Playgroud)

这可能吗?

Ale*_*ara 6

MDN 上所述,apply代理方法用于代理对代理对象本身的函数调用,而不是对对象方法的调用。

它仅适用于函数(作为代理目标),而不适用于常规对象实例,但它的工作方式如下:

var p = new Proxy(function() {}, {
    apply: function() {
        console.log('apply called');
    }
});
p();
Run Code Online (Sandbox Code Playgroud)

这个旅程的最终目的是我想 根据属性是被读取还是被调用来返回一个不同的值。

直接做你想做的事情是不可能的,也没有真正的意义。调用就是读取属性。

  • @Jochem 啊哈!我错误地认为它可以与常规对象一起使用。原来它只适用于函数,这是有道理的。请参阅我更新的答案。 (2认同)

小智 6

我知道这是一个问题,但我也遇到了这个问题,我找到了一种方法来做你想做的事情。所以这是为了将来参考,因为我没有在其他地方找到正确的解决方案。

简短版本:访问一个对象(或一个类)内的函数本质上get是调整具有该函数的对象的属性。诀窍是返回另一个代理,apply以便您可以正确代理这些功能。

考虑以下对象:

const myObject = {
  a: 'Hello world!',
  b: x => x * x
};
Run Code Online (Sandbox Code Playgroud)

访问ab都应被代理的 捕获get,因为它们是对象的属性。您应该捕获所有get,然后过滤函数。一旦你有了一个函数,你就会返回一个新的代理,它用Proxy.apply. 然后,为了让函数按预期执行,Proxy.apply我们在内部返回一个Reflect.apply,它按预期使用正确的参数调用原始函数。

你最终会得到这个代码:

const myProxyObject = new Proxy(myObject, {
  get(target, propKey, receiver) {    
    // Calling functions
    if (typeof target[propKey] === 'function') {
      return new Proxy(target[propKey], {
        apply(applyTarget, thisArg, args) {
          console.log(`Calling ${thisArg.constructor.name}.${propKey}(${args})`);
          return Reflect.apply(applyTarget, thisArg, args);
        }
      });
    }

    // Accessing properties
    if (target.hasOwnProperty(propKey)) {
      console.log(`Get value of ${target.constructor.name}.${propKey}`);
      console.log(`Value: ${target[propKey]}`);
    }

    return target[propKey];
  }
});
Run Code Online (Sandbox Code Playgroud)

jsfiddle 上的演示

您不会得到函数的结果,因为那需要您执行它。

注意:可以将它与一起使用,并且效果很好。唯一需要注意的是,您的代理也将捕获所有内部功能。为了防止记录数十个valueOfs,我强烈建议使用类似 isNative 函数来测试一个函数是否是原生的