it-roy-ru.com

Могу ли я расширить 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);

Кто-нибудь знает, почему я могу получить эту ошибку? Это ошибка в Вавилоне? Что должно произойти, когда вы пытаетесь расширить прокси?

25
John L.

Нет, класс ES2015 не может расширяться Proxy1,.

Прокси-объекты имеют очень нетипичную семантику и считаются «экзотическими объектами» в ES2015, что означает, что они «не имеют поведения по умолчанию для одного или нескольких основных внутренних методов, которые должны поддерживаться всеми объектами». У них нет никакого прототипа, где вы обычно получаете большинство поведения для типа, который вы расширяете. С раздел 26.2.2: «Свойства прокси-конструктора» в спецификации :

Конструктор Proxy не имеет свойства prototype, потому что экзотические прокси-объекты не имеют внутреннего слота [[Prototype]], который требует инициализации.

Это не ограничение Вавилона. Если вы попытаетесь расширить Proxy в Chrome, где он и синтаксис класса поддерживаются изначально, вы все равно получите похожую ошибку:

Uncaught TypeError: класс расширяет значение, не имеет допустимого свойства прототипа undefined

1 «Нет» - это практический ответ. Тем не менее, Александр О'Мара отметил, что если вы присваиваете значение Proxy.prototype (брутто!), Его можно расширить, по крайней мере, в некоторых браузерах. Мы немного поэкспериментировали с этим . Из-за поведения экзотических экземпляров Proxy это не может быть использовано для достижения гораздо большего, чем вы могли бы сделать с помощью функции, обертывающей конструктор, и некоторое поведение не выглядит согласованным между браузерами (я не уверен, чего ожидает спецификация если ты это сделаешь). Пожалуйста, не пытайтесь делать что-либо подобное в серьезном коде.

24
Jeremy Banks

Ну, я забыл об этом вопросе, но кто-то недавно проголосовал за него. Даже если вы технически не можете расширить прокси-сервер, существует способ заставить экземпляр класса создать экземпляр как прокси-сервер и заставить все его подклассы создавать экземпляры как прокси-серверы с теми же функциями дескриптора свойства (я проверял это только в 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;
39
John L.

От @John L. самоответ:
Внутри конструктора мы можем использовать Proxy, чтобы обернуть вновь созданный экземпляр. Не нужно расширять прокси. 

Пример, укажите наблюдаемую точку из существующего класса 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
            }
        })
    }
}

тестовое задание:

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)
6
Joseph Merdrignac
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 не является оригинальным прототипом, он был прокси, вроде. 

0
Weizhe Ding

Бабель не поддерживает Прокси, просто потому что не может. Так что, пока браузеры не добавят поддержку, она не существует.

Из документов Babel: «Неподдерживаемая функция Из-за ограничений ES5, Прокси не могут быть перенесены или заполнены»

0
omerts
class c1 {
    constructor(){
        this.__proto__  = new Proxy({}, {
            set: function (t, k, v) {
                t[k] = v;
                console.log(t, k, v);
            }
        });
    }
}

d = новый c1 (); d.a = 123;

0
user3027221