John L. John L. - 1 year ago 80
Javascript Question

Can I extend Proxy with an ES2015 class?

I tried to extend Proxy, like so:

class ObservableObject extends Proxy {}

I used Babel to transpile it to ES5, and I got this error in the browser:

app.js:15 Uncaught TypeError: Object prototype may only be an Object or null: undefined

I looked at the line of code it pointed to. Here's that portion of the code with arrows pointing to the offending line of code:

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;

Does anyone know why I might be getting this error? Is this a bug in Babel? What is supposed to happen when you try to extend Proxy?

Answer Source

No, an ES2015 class cannot extend Proxy1.

Proxy objects have very atypical semantics and are considered "exotic objects" in ES2015, meaning that they do "not have the default behaviour for one or more of the essential internal methods that must be supported by all objects". They do not have any prototype, which is where you'd normally get most of the behaviour for a type you're extending. From section 26.2.2: "Properties of the Proxy Constructor" in the specification:

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

This is not a limitation of Babel. If you attempt to extend Proxy in Chrome, where it and the class syntax are both natively supported, you'll still get a similar error:

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

1 "No" is the practical answer. However, Alexander O'Mara pointed out that if you assign a value to Proxy.prototype (gross!), it does become possible to extend, at least in some browsers. We experimented with this a little. Due to the behaviour of exotic Proxy instances this can't be used to accomplish much more than you could do with a function wrapping the constructor, and some behaviour does not appear to be consistent between browsers (I'm not sure what the specification expects if you do this). Please don't attempt anything like this in serious code.