搜索

首页  >  问答  >  正文

Node.js中使用Proxy模拟PHP的__callStatic属性的方法

<p>我正在尝试在Node.js中创建与PHP <code>__callStatic</code> 魔术方法相同的行为。</p> <p>我正在尝试使用<code>Proxy</code>来实现,但我不确定是否是最佳选择。</p> <p> <pre class="snippet-code-js lang-js prettyprint-override"><code>class Test { constructor() { this.num = 0 } set(num) { this.num = this.num + num return this } get() { return this.num } } const TestFacade = new Proxy({}, { get: (_, key) => { const test = new Test() return test[key] } }) // 执行方法链以get结束 console.log(TestFacade.set(10).set(20).get()) // 期望结果: 30 // 返回结果: 0 // 开始一个新的执行方法链,并在第一个set中再次实例化Test类 console.log(TestFacade.set(20).set(20).get()) // 期望结果: 40 // 返回结果: 0</code></pre> </p> <p>问题在于每次我尝试访问<code>TestFacade</code>的属性时,<code>get</code>陷阱都会被触发。我需要的行为是,当调用<code>set</code>方法时,它将返回<code>Test</code>类的<code>this</code>,我甚至可以保存该实例以供以后使用!</p> <pre class="brush:php;toolbar:false;">const testInstance = TestFacade.set(10) // set方法返回`Test`的`this`而不是Proxy</pre> <p>如果有什么不清楚的地方,请告诉我。</p>
P粉653045807P粉653045807464 天前545

全部回复(1)我来回复

  • P粉549986089

    P粉5499860892023-09-05 00:15:19

    我不知道这是否是最佳选择。但是我通过在get陷阱中返回一个新的代理来解决了这个问题,该代理使用apply陷阱将test类实例绑定到方法中:

    class Facade {
      static #facadeAccessor
    
      static createFacadeFor(provider) {
        this.#facadeAccessor = provider
    
        return new Proxy(this, { get: this.__callStatic.bind(this) })
      }
    
      static __callStatic(facade, key) {
        /**
         * 访问Facade类的方法而不是提供者的方法。
         */
        if (facade[key]) {
          return facade[key]
        }
    
        const provider = new this.#facadeAccessor()
    
        const apply = (method, _this, args) => method.bind(provider)(...args)
    
        if (provider[key] === undefined) {
          return undefined
        }
    
        /**
         * 访问类的属性。
         */
        if (typeof provider[key] !== 'function') {
          return provider[key]
        }
    
        return new Proxy(provider[key], { apply })
      }
    }
    
    class Test {
      num = 0
    
      set(num) {
        this.num = this.num + num
    
        return this
      }
    
      get() {
        return this.num
      }
    }
    
    const TestFacade = Facade.createFacadeFor(Test)
    
    console.log(TestFacade.set(10).set(20).get()) // 30
    console.log(TestFacade.set(5).set(5).get()) // 10
    
    const testInstance = TestFacade.set(10)
    
    console.log(testInstance.num) // 10
    console.log(testInstance.get()) // 10
    console.log(testInstance.set(10).get()) // 20

    回复
    0
  • 取消回复