【问题标题】:Is there a way to use Javascript ES6 Proxy to spy on Object Methods [duplicate]有没有办法使用 Javascript ES6 代理来监视对象方法 [重复]
【发布时间】:2020-04-29 04:57:57
【问题描述】:

有没有可能,给定以下对象

let target = {
 foo:0,
 result:[],
 bar(){
   //some code
 }
}

然后将所述对象包装在 Proxy()

let handler = {
  get(){
    // code here
  },
  apply(){
    // code here
   }
 }

 target = new Proxy(target,handler);

捕捉到bar() 的调用并将结果保存到results:[]

我试了几次

let target = {
    called:0,
    results:[],
    foo(bar){
        return bar;
    },
}

let handler = {
    get(target,prop){
        console.log('Get Ran')
        return target[prop];
    },
    apply(target,thisArg,args){
        console.log('Apply Ran')
        // never runs
    }
}

target = new Proxy(target,handler);
target.foo();

这段代码错过了 [[ apply ]] 但捕获了 [[ get ]] (如果内存服务,对象方法调用作为两个操作完成,[[ get ]] [[ apply ]])

let target = {
    called:0,
    results:[],
    foo(bar){
        return bar;
    },
}

let handler = {
    get(target,prop){
        return target[prop];
    },
    apply(target,thisArg,args){
        let product = target.apply(thisArg,args)
        return product;
    },
}

let prox = new Proxy(target.foo,handler);
    console.log(prox('hello'));

如果我将对象方法包装在代理中,它会捕获 [[ apply ]] 但我失去了对原始对象( this )的引用,因此无法访问结果数组

我还尝试将方法代理嵌套在对象代理中。

有什么想法吗?

CodeSandBox of my actual code

// 代理文档

Proxy MDN

Javascript.info/proxy

// 其他问题,关于代理,但不是这个用例

Understanding ES6 javascript proxies

【问题讨论】:

  • 看起来你的目标没有引用它自己的任何属性。那么它真的需要绑定到this 吗?此外,除非您使用代理版本,否则您将无法监听函数调用。为什么不通过将函数包装在函数中来添加您想要的额外功能?您能否举一个代码框示例来说明您要实现的目标?
  • @DanielDuong 是的!我完全做了一个,但忽略了将它添加到我的原始帖子中回答你的问题,作为一个有趣的副项目,我正在制作一个 Jest 的仿冒版本,以便更直观地理解它,这是专门为模拟功能,模拟函数存储有关其调用方式,调用结果的详细信息等......所以这就是我来自的地方

标签: javascript ecmascript-6 proxy


【解决方案1】:

根据spec

如果其 [[ProxyTarget]] 内部槽的初始值是具有 [[Call]] 内部方法的对象,则代理外来对象仅具有 [[Call]] 内部方法。

如果目标是function,下面确实会捕获调用

(new Proxy(() => 'hello', { apply: () => console.log('catched') }))() // 'catched

反过来,如果目标没有调用方法,那么就没有代理

try {
  (new Proxy({}, { apply: () => console.log('catched') }))() // throws
} catch (e){ console.log('e', e.message)}

因此提示可能是代理 [get] 而不是返回值(作为函数 bar,代理该值以捕获最终调用

const p = new Proxy(
  { results: [], bar: () => { console.log('rywhite') } }, {
  get: (target, prop) => {
    if (prop !== 'bar') return target[prop]
    return new Proxy (target.bar, {
      apply () {
        target.results.push('what')
      }
    })
  }
})
p.bar // nothing bud'
p.bar(); console.log('res', p.results)
p.bar(); console.log('res', p.results)
p.bar(); console.log('res', p.results)

编辑:注意:不必每次都创建新代理

在下面的代码中,返回相同的代理大约快两倍

const N = 1e6
{
  const target = { results: 0, bar: () => { console.log('rywhite') } }
  const p = new Proxy(
    target, {
    get: (() => {
      const barProxy = new Proxy (target.bar, {
        apply () {
          target.results++
        }
      })
      return (target, prop) => {
        if (prop !== 'bar') return target[prop]
        return barProxy
      }
    })()
  })
  console.time('go')
  for (let i = 0; i < N; ++i) { p.bar() }
  console.timeEnd('go')
  console.log('res', p.results)
}
{
  const p = new Proxy(
    { results: 0, bar: () => { console.log('rywhite') } }, {
      get: (target, prop) => {
        if (prop !== 'bar') return target[prop]
        return new Proxy (target.bar, {
          apply () {
            target.results++
          }
        })
      }
    })
  console.time('neweverytime')
  for (let i = 0; i < N; ++i) { p.bar() }
  console.timeEnd('neweverytime')
  console.log('res', p.results)
}

【讨论】:

    猜你喜欢
    • 2020-07-15
    • 1970-01-01
    • 2011-09-07
    • 1970-01-01
    • 1970-01-01
    • 2010-09-14
    • 2018-10-27
    • 2021-12-19
    • 2013-04-02
    相关资源
    最近更新 更多