Могу ли я расширить Proxy с помощью класса ES2015?
Я пытался расширить прокси-сервер так:
class ObservableObject extends Proxy {}
Я использовал Babel, чтобы передать его ES5, и я получил эту ошибку в браузере:
app.js:15 Uncaught TypeError: Object prototype may only be an Object or null: undefined
Я посмотрел на строку кода, на которую он указывал. Вот эта часть кода со стрелками, указывающими на строку нарушения кода:
var ObservableObject = exports.ObservableObject = function (_Proxy) {
_inherits(ObservableObject, _Proxy); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
function ObservableObject() {
_classCallCheck(this, ObservableObject);
return _possibleConstructorReturn(this, Object.getPrototypeOf(ObservableObject).apply(this, arguments));
}
return ObservableObject;
}(Proxy);
Кто-нибудь знает, почему я могу получить эту ошибку? Это ошибка в Вавилоне? Что должно произойти, когда вы пытаетесь расширить прокси?
Ответы
Ответ 1
Нет, класс ES2015 не может расширять Proxy
1.
Объекты прокси имеют очень нетипичную семантику и считаются "экзотическими объектами" в ES2015, что означает, что они "не имеют поведения по умолчанию для одного или нескольких основных внутренних методов, которые должны поддерживаться всеми объектами". У них нет прототипа, в котором вы обычно получаете большую часть поведения для типа, который вы расширяете. Из раздела 26.2.2: "Свойства прокси-конструктора" в спецификации:
Конструктор Proxy
не обладает свойством prototype
потому что в прокси-экзотических объектах нет внутреннего слота [[Prototype]], требующего инициализации.
Это не ограничение Вавилона. Если вы попытаетесь расширить Proxy
в Chrome, где он и синтаксис класса поддерживаются как изначально, вы по-прежнему получите аналогичную ошибку:
Uncaught TypeError: Класс extends value не имеет допустимого свойства прототипа undefined
1 "Нет" - это практический ответ.Однако Александр О'Мара отметил, что если вы присвоите значение Proxy.prototype
(брутто!), Становится возможным расширение, по крайней мере, в некоторых браузерах.Мы немного экспериментировали с этим.Из-за поведения экзотических экземпляров Proxy это невозможно использовать для выполнения гораздо большего, чем вы могли бы сделать с помощью функции, обертывающей конструктор, и некоторое поведение не кажется согласованным между браузерами (я не уверен, что ожидает спецификация если вы это сделаете).Пожалуйста, не пытайтесь делать что-либо подобное в серьезном коде.
Ответ 2
Ну, я забыл об этом вопросе, но кто-то недавно поддержал его. Даже если вы технически не можете расширять прокси-сервер, есть способ заставить класс создавать экземпляр в качестве прокси-сервера и заставить все его подклассы создавать экземпляры в качестве прокси-сервера с теми же функциями дескриптора свойств (я тестировал это только в Chrome):
class ExtendableProxy {
constructor() {
return new Proxy(this, {
set: (object, key, value, proxy) => {
object[key] = value;
console.log('PROXY SET');
return true;
}
});
}
}
class ChildProxyClass extends ExtendableProxy {}
let myProxy = new ChildProxyClass();
// Should set myProxy.a to 3 and print 'PROXY SET' to the console:
myProxy.a = 3;
Ответ 3
Из ответа @John L.:
Внутри конструктора мы можем использовать прокси для переноса вновь созданного экземпляра. Не нужно расширять прокси.
Например, укажите наблюдаемую точку из существующего класса Point:
class Point {
constructor(x, y) {
this.x = x
this.y = y
}
get length() {
let { x, y } = this
return Math.sqrt(x * x + y * y)
}
}
class ObservedPoint extends Point {
constructor(x, y) {
super(x, y)
return new Proxy(this, {
set(object, key, value, proxy) {
if (object[key] === value)
return
console.log('Point is modified')
object[key] = value
}
})
}
}
test:
p = new ObservedPoint(3, 4)
console.log(p instanceof Point) // true
console.log(p instanceof ObservedPoint) // true
console.log(p.length) // 5
p.x = 10 // "Point is modified"
console.log(p.length) // 5
p.x = 10 // nothing (skip)
Ответ 4
Бабель не поддерживает прокси, просто потому, что он не может. Поэтому, пока браузеры не поддерживают поддержку, ее не существует.
Из документов Babel: "Неподдерживаемая функция. Из-за ограничений ES5 Proxies нельзя переполнять или заполнять"
Ответ 5
class c1 {
constructor(){
this.__proto__ = new Proxy({}, {
set: function (t, k, v) {
t[k] = v;
console.log(t, k, v);
}
});
}
}
d = новый c1(); da = 123;
Ответ 6
class A { }
class MyProxy {
constructor(value, handler){
this.__proto__.__proto__ = new Proxy(value, handler);
}
}
let p = new MyProxy(new A(), {
set: (target, prop, value) => {
target[prop] = value;
return true;
},
get: (target, prop) => {
return target[prop];
}
});
console.log("p instanceof MyProxy", p instanceof MyProxy); // true
console.log("p instanceof A", p instanceof A); // true
p является своего рода MyProxy
и он был расширен одновременно A
классом. A не является оригинальным прототипом, он проксирован, вроде.