有没有一种方法可以使用Javascript ES6代理监视对象方法

时间:2020-04-29 04:57:57

标签: javascript ecmascript-6 proxy

考虑到以下对象,有可能

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

1 个答案:

答案 0 :(得分: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)
}