48

我尝试扩展代理,如下所示:

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 中的错误吗?当您尝试扩展代理时应该发生什么?

4

6 回答 6

89

好吧,我忘记了这个问题,但最近有人赞成。即使您在技术上无法扩展代理,也有一种方法可以强制类实例化为代理并强制其所有子类实例化为具有相同属性描述符函数的代理(我只在 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;
于 2016-11-21T06:57:05.790 回答
38

不,ES2015 类不能扩展Proxy1

代理对象具有非常非典型的语义,在 ES2015 中被认为是“外来对象”,这意味着它们“没有所有对象必须支持的一种或多种基本内部方法的默认行为”。它们没有任何原型,这是您通常会在其中获得您正在扩展的类型的大部分行为的地方。来自规范中的第 26.2.2 节:“代理构造函数的属性”

构造Proxy函数没有prototype属性,因为代理外来对象没有需要初始化的 [[Prototype]] 内部槽。

这不是 Babel 的限制。如果你尝试Proxy在 Chrome 中进行扩展,它和类语法都是原生支持的,你仍然会收到类似的错误:

未捕获的类型错误:类扩展值没有有效的原型属性未定义

1 “否”是实际答案。然而,Alexander O'Mara指出,如果你给Proxy.prototype(gross!) 赋值,它确实可以扩展,至少在某些浏览器中是这样。我们对此进行了一些试验。由于外来 Proxy 实例的行为,与使用包装构造函数的函数相比,它不能用于完成更多工作,并且某些行为在浏览器之间似乎不一致(我不确定规范期望什么如果你这样做)。请不要在严肃的代码中尝试这样的事情。

于 2016-06-09T00:01:23.193 回答
15

来自@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)
于 2018-03-05T10:16:45.273 回答
3
class c1 {
    constructor(){
        this.__proto__  = new Proxy({}, {
            set: function (t, k, v) {
                t[k] = v;
                console.log(t, k, v);
            }
        });
    }
}

d = 新 c1(); da = 123;

于 2016-08-16T17:13:05.377 回答
0

Babel 不支持 Proxy,只是因为它不能。因此,在浏览器添加支持之前,它不存在。

来自 Babel 文档:“不支持的功能由于 ES5 的限制,代理不能被转译或填充”

于 2016-06-09T00:01:05.157 回答
0
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它同时被Aof 类扩展。A 不是原始原型,它是代理的,有点。

于 2017-07-28T07:52:40.820 回答