#javascript #ecmascript-6 #es6-class #es6-proxy
#javascript #ecmascript-6 #es6-класс #es6-прокси
Вопрос:
У меня есть простой класс ES6, например:
class Ring extends Array {
insert (item, index) {
this.splice(index, 0, item);
return this;
}
}
Я хочу сделать так, чтобы индексация для кольцевых объектов переносилась, так что new Ring(1, 2, 3)[3]
возвращает 1, new Ring(1, 2, 3)[-1]
возвращает 3 и так далее. Возможно ли это в ES6? Если да, то как мне это реализовать?
Я читал о прокси, которые позволяют полностью настроить геттер, но я не могу понять, как применить прокси к классу. Я справился с этим:
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
теперь это кольцевой объект, который поддерживает перенос индексов. Проблема в том, что мне пришлось бы определять кольцевые объекты подобным образом каждый раз. Есть ли способ применить этот прокси к классу так, чтобы вызов new Ring()
возвращал его?
Комментарии:
1. Просто оберните
new Proxy (...)
с помощью функции конструктора и вызовите ее сnew
помощью . Да, вы не можете сделать это без прокси.
Ответ №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' amp;amp; /^-?d $/.test(name))
return target[(name % len len) % len];
return target[name];
}
});
}
insert (item, index) {
this.splice(index, 0, item);
return this;
}
}
Комментарии:
1. Ну … кажется, это работает отлично! Я не понимал, что функция конструктора может явно возвращать значение…
2. Ага… Вау, я никогда не знал, что вы можете возвращать значение из конструктора в классах ES6…
3. Да, это так . В большинстве случаев это было бы неоправданно, но это именно тот случай.
Ответ №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];
}
}
)
Комментарии:
1. Хм… Это довольно близко, за исключением того, что он не поддерживает
new
.
Ответ №3:
В основном у вас есть два варианта:
-
Оберните a
Proxy
вокруг каждого экземпляраconst handler = { get(target, name) { var len = target.length; if (typeof name === 'string' amp;amp; /^-?d $/.test(name)) return target[(name % len len) % len]; return target[name]; } }; class Ring extends Array { constructor() { super() return new Proxy(this, handler); } … }
-
оберните a
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' amp;amp; /^-?d $/.test(name)) { if ( name < 0) return receiver[(name % len) len]; if ( name > len-1) return receiver[name % len]; } return target[name]; } });
Комментарии:
1. Второй метод, похоже, не работает для меня. Я попытался использовать только прокси-часть для расширения класса Number, и мне удалось заставить это работать, изменив оба экземпляра
Number.prototype
наNumber.prototype.__proto__
.2. @ETHproductions Не уверен, зачем вам создавать
Number.prototype
прокси? И вам, вероятно, следует изменить a.__proto__
, поскольку это вводит другой объект в цепочку прототипов.