【问题标题】:Using Proxy.apply() on Node.js does not work. Is this a bug or am I doing it wrong?在 Node.js 上使用 Proxy.apply() 不起作用。这是一个错误还是我做错了?
【发布时间】:2016-10-05 10:14:21
【问题描述】:

我正在使用代理来代理对象。 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?')        
    }
})

这样,我可以将某些内容分配给p 或返回某些内容,即使它不存在。 例如,当我让 getter 函数返回这个时

get(target, name) {
    return 'getting ' + name
},

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

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

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

get(target, name) {
    return function() { return 'this is '+name } 
},

我可以调用该属性而不必存在它。

console.log(
    p.flappy() // this is flappy!
)

那么 apply 什么时候被调用呢?不在我刚刚在这里展示的 sn-p 中,在这种情况下也没有:

p.foo = function() {
    console.log('yay!')
    return 'foo!'
}

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

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

   p.someNewProperty // return what the getter function returns

    p.anotherProperty() // return something else here because this is a function call

这可能吗?

【问题讨论】:

标签: javascript node.js proxy call apply


【解决方案1】:

几年后……

是的,你可以!您可以根据是读取还是调用属性返回不同的值!

const authUser = { id: 1 }

const user = new Proxy(function () {}, {
    get (target, property) {
    return authUser.id
  },
  apply (target, thisArg, args) {
    // some stuff to get user
    return { id: args[0] }
  }
})

console.log(user.id)
console.log(user(2).id)

或者您可以使用两步代理。

const authUser = { id: 1 }

const user = new Proxy(function () {}, {
  get (target, property) {
    return userProxy(authUser.id, property)
  },
  apply (target, thisArg, args) {
    return userProxy(args[0])
  }
})

function userProxy(id, property) {
  // some stuff to get user
  const user = { id }

  return property ? user[property] : new Proxy(user, {
    get (target, property) {
      return user[property]
    }
  })
}

console.log(user.id)
console.log(user(2).id)

【讨论】:

    【解决方案2】:

    作为documented on MDNapply 代理方法用于代理代理对象本身的函数调用,而不是对象方法的调用。

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

    var p = new Proxy(function() {}, {
        apply: function() {
            console.log('apply called');
        }
    });
    p();
    

    此旅程的最终目的是我想根据是否正在读取或调用属性返回一个不同值。

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

    【讨论】:

    • 对不起,伙计,但这不是真的。当您在这些示例中调用 p() 时,它只会返回一个错误。 “p 不是函数”
    • @Jochem 我不在我的桌面上,但我有理由确定我的答案的核心是正确的。您的代码中可能存在实现错误。你得到什么错误?
    • 我已经复制粘贴了我的代码,在回答你之前我尝试调用 p() 以确保我没有浪费你的时间。
    • @Jochem 啊哈!我错误地认为它适用于常规对象。原来它只适用于函数,这是有道理的。请参阅我的更新答案。
    • 这也把我绊倒了。 Proxy 的 target 必须是一个函数。
    【解决方案3】:

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

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

    考虑以下对象:

    const myObject = {
      a: 'Hello world!',
      b: x => x * x
    };
    

    访问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];
      }
    });
    

    Demo on jsfiddle

    你没有得到函数的结果,因为那需要你执行它。

    注意:可以将它与 classes 一起使用,并且效果非常好。唯一需要注意的是,您的代理也将捕获所有内部函数。为了防止记录几十个valueOfs,我强烈建议使用like this isNative function来测试一个函数是否是本机的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-14
      相关资源
      最近更新 更多