开发者问题收集

我可以使用 ES2015 类扩展 Proxy 吗?

2016-06-08
20489

我尝试扩展 Proxy,如下所示:

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);

有人知道我为什么会收到此错误吗?这是 Babel 中的错误吗?当您尝试扩展 Proxy 时应该发生什么?

3个回答

好吧,我忘记了这个问题,但最近有人点赞了。尽管从技术上讲你无法扩展代理,但有一种方法可以强制一个类实例化为代理,并强制其所有子类实例化为具有相同属性描述符函数的代理(我只在 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;
John L.
2016-11-21

不可以,ES2015 类无法扩展 Proxy 1

代理对象具有非常不典型的语义,在 ES2015 中被视为“异国对象”,这意味着它们“不具备所有对象必须支持的一个或多个基本内部方法的默认行为”。它们没有任何原型,而您通常会从原型中获取要扩展类型的大多数行为。来自规范中的 第 26.2.2 节:“代理构造函数的属性”

The Proxy constructor does not have a prototype property because proxy exotic objects do not have a [[Prototype]] internal slot that requires initialization.

这不是 Babel 的限制。如果您尝试在 Chrome 中扩展 Proxy ,该浏览器本身支持该类语法,那么您仍会收到类似的错误:

Uncaught TypeError: Class extends value does not have valid prototype property undefined

1 “否”是实际答案。但是, Alexander O'Mara 指出,如果您为 Proxy.prototype 分配一个值(太恶心了!),则确实可以扩展,至少在某些浏览器中是这样的。 我们对此进行了一些实验 。由于异域代理实例的行为,这不能用于完成比使用包装构造函数的函数所能完成的更多的事情,并且某些行为似乎在浏览器之间不一致(我不确定如果您这样做,规范会期望什么)。请不要在严肃的代码中尝试任何类似的事情。

Jeremy
2016-06-09

来自@John L. 的自我回应:
在构造函数内部,我们可以使用 Proxy 来包装新创建的实例。无需扩展 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)
Joseph Merdrignac
2018-03-05