简体   繁体   English

JavaScript中的自定义数组类getter

[英]Custom Array-like getter in JavaScript

I have a simple ES6 class, like so: 我有一个简单的ES6类,如下所示:

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

I want to make it so that the indexing for Ring objects wraps, so that new Ring(1, 2, 3)[3] returns 1, new Ring(1, 2, 3)[-1] returns 3, and so on. 我想这样做,以便Ring对象的索引包装,以便new Ring(1, 2, 3)[3]返回1, new Ring(1, 2, 3)[-1]返回3,依此类推。 Is this possible in ES6? 这可能在ES6中吗? If so, how would I implement it? 如果是这样,我将如何实现它?

I've read about proxies, which allow a completely customized getter, but I can't figure out how to apply a proxy to a class. 我已经阅读了代理,它允许完全自定义的getter,但我无法弄清楚如何将代理应用于类。 I did manage this: 我确实管理了这个:

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 is now a Ring object that supports wrapping indices. myRing现在是一个支持包装索引的Ring对象。 The problem is that I'd have to define Ring objects like that every time. 问题是我每次都必须定义像这样的Ring对象。 Is there a way to apply this proxy to the class such that calling new Ring() returns it? 有没有办法将这个代理应用于类,以便调用new Ring()返回它?

Basically it is 基本上是

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;
  }
}

Warning: This is an ugly hack 警告:这是一个丑陋的黑客

This is a rather simple approach when you think about it. 当你想到它时,这是一个相当简单的方法。

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

This defined a function ClassToProxy . 这定义了一个函数ClassToProxy The first argument is the class you want to add behavior too, and the second is the handler. 第一个参数是您要添加行为的类,第二个参数是处理程序。


Here's example usage: 以下是示例用法:

const Ring = ClassToProxy(

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

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

You basically have two choices: 你基本上有两个选择:

  • Wrap a Proxy around each instance 围绕每个实例包装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); } … } 
  • wrap a Proxy around the prototype of your class 围绕您的类的原型包装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]; } }); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM