[英]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.