【问题标题】:Custom Array-like getter in JavaScriptJavaScript中的自定义类数组getter
【发布时间】:2016-10-01 02:19:03
【问题描述】:

我有一个简单的 ES6 类,如下所示:

class Ring extends Array {
    insert (item, index) {
        this.splice(index, 0, item);
        return this;
    }
}

我想让 Ring 对象的索引换行,这样new Ring(1, 2, 3)[3] 返回 1,new Ring(1, 2, 3)[-1] 返回 3,依此类推。这在 ES6 中可能吗?如果是这样,我将如何实现它?

我读过代理,它允许完全自定义的 getter,但我不知道如何将代理应用于类。我确实做到了:

var myRing = new Proxy (Ring.prototype, {
    get: function (target, name) {
        var len = target.length;
        if (/^-?\d+$/.test(name))
            return target[(name % len + len) % len];
        return target[name];
    }
});

myRing 现在是一个支持包装索引的 Ring 对象。问题是我每次都必须像这样定义 Ring 对象。有没有办法将此代理应用于类,以便调用 new Ring() 返回它?

【问题讨论】:

  • 只需用构造函数包装new Proxy (...) 并用new 调用它。是的,没有代理你不能这样做。

标签: javascript ecmascript-6 es6-class es6-proxy


【解决方案1】:

基本上是这样

class ProxyRing extends Array {
  constructor(...args) {
    super(...args)

    return new Proxy(this, {
      get: function (target, name) {
          var len = target.length;
          if (typeof name === 'string' && /^-?\d+$/.test(name))
              return target[(name % len + len) % len];
          return target[name];
      }
    });
  }

  insert (item, index) {
      this.splice(index, 0, item);
      return this;
  }
}

【讨论】:

  • 嗯...这似乎工作得很好!我没有意识到构造函数可以显式返回一个值...
  • 嗯...哇,我从来不知道你可以从 ES6 的类中的构造函数返回一个值...
  • 是的,they are。在大多数情况下,这是不合理的,但情况正是如此。
【解决方案2】:

警告:这是一个丑陋的黑客攻击

仔细想想,这是一种相当简单的方法。

function ClassToProxy(_class, handler) {
    return (...args) => new Proxy(new _class(...args), handler);
}

这定义了一个函数ClassToProxy。第一个参数是你要添加行为的类,第二个是处理程序。


以下是示例用法:

const Ring = ClassToProxy(

    // Class
    class Ring {
        constructor(...items) {
            this.items = items;
        }
    },

    // Handler
    {
        get: function(target, name) {
            return target.items[name];
        }
    }
)

【讨论】:

  • 嗯...非常接近,只是它不支持new
【解决方案3】:

你基本上有两种选择:

  • 在每个实例周围包裹一个Proxy

    const handler = {
        get(target, name) {
            var len = target.length;
            if (typeof name === 'string' && /^-?\d+$/.test(name))
                return target[(name % len + len) % len];
            return target[name];
        }
    };
    class Ring extends Array {
        constructor() {
            super()
            return new Proxy(this, handler);
        }
        …
    }
    
  • 在你的类原型周围包裹一个Proxy

    class Ring extends Array {
        constructor() {
            super()
        }
        …
    }
    Ring.prototype = new Proxy(Ring.prototype, {
        get(target, name, receiver) {
            var len = target.length;
            if (typeof name === 'string' && /^-?\d+$/.test(name)) {
                if (+name < 0)
                    return receiver[(name % len) + len];
                if (+name > len-1)
                    return receiver[name % len];
            }
            return target[name];
        }
    });
    

【讨论】:

  • 第二种方法似乎对我不起作用。我尝试仅使用代理部分来扩展 Number 类,并且通过将 Number.prototype 的两个实例更改为 Number.prototype.__proto__ 来设法使其工作。
  • @ETHproductions 不知道为什么要让Number.prototype 成为代理?您可能应该更改.__proto__,因为这确实会在原型链中引入另一个对象。
猜你喜欢
  • 2017-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-09
  • 2017-10-31
  • 1970-01-01
  • 1970-01-01
  • 2017-04-13
相关资源
最近更新 更多