Custom array-like array in JavaScript

I have a simple ES6 class, for example:

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

I want to make the indexing of Ring objects wrap so that new Ring(1, 2, 3)[3] returns 1, new Ring(1, 2, 3)[-1] returns 3, and so on. Is this possible in ES6? If so, how do I implement it?

I read about proxies that allow getter to be fully configured, but I cannot figure out how to apply proxies to a class. I dealt with 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 now a Ring object that supports wrapping indices. The problem is that I have to define Ring objects like this every time. Is there a way to apply this proxy to a class so that calling new Ring() returns it?

+8
javascript ecmascript-6 es6-proxy
source share
3 answers

Mainly

 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; } } 
+5
source share

Warning: This is an ugly hack

This is a pretty simple approach when you think about it.

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

This defined the ClassToProxy function. The first argument is the class to which you want to add the behavior, and the second is the handler.


Here's a usage example:

 const Ring = ClassToProxy( // Class class Ring { constructor(...items) { this.items = items; } }, // Handler { get: function(target, name) { return target.items[name]; } } ) 
+3
source share

You basically have two options:

  • Wrap Proxy around each instance

     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 the Proxy around the prototype of your class

     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]; } }); 
0
source share

All Articles