How and why would I write a class that extends null?

JavascriptEcmascript 6Es6 Class

Javascript Problem Overview


JavaScript's class syntax, added in ES6, apparently makes it legal to extend null:

class foo extends null {}

Some Googling reveals that it was suggested on ES Discuss that such declarations be made an error; however, other commenters argued for them to be left legal on the basis that

> someone might want to create a class that has a {__proto__: null} prototype

and that side of the argument ultimately prevailed.

I can't make much sense of this hypothetical use case. For one thing, while the declaration of such a class is legal, it seems that instantiating a class declared in this way isn't. Trying to instantiate the class foo from above in Node.js or Chrome gives me the wonderfully daft error

TypeError: function is not a function

while doing the same in Firefox gives me

TypeError: function () {
} is not a constructor

It doesn't help to define a constructor on the class, as shown in MDN's current example of the feature; if I try to instantiate this class:

class bar extends null {
  constructor(){}
}

then Chrome/Node tell me:

ReferenceError: this is not defined

and Firefox tells me:

ReferenceError: |this| used uninitialized in bar class constructor

What is all this madness? Why are these null-extending classes not instantiable? And given that they're not instantiable, why was the possibility of creating them deliberately left in the spec, and why did some MDN author think that it was noteworthy enough to document? What possible use case is there for this feature?

Javascript Solutions


Solution 1 - Javascript

EDIT (2021): TC39, which specifies JavaScript still hasn't resolved exactly how this is supposed to work. That needs to happen before browsers can consistently implement it. You can follow the latest efforts here.


Original answer:

Instantiating such classes is meant to work; Chrome and Firefox just have bugs. Here's Chrome's, here's Firefox's. It works fine in Safari (at least on master).

There used to be a bug in the spec which made them impossible to instantiate, but it's been fixed for a while. (There's still a related one, but that's not what you're seeing.)

The use case is roughly the same as that of Object.create(null). Sometimes you want something which doesn't inherit from Object.prototype.

Solution 2 - Javascript

To answer the second part:

> I can't make much sense of this hypothetical use case.

That way, your object won't have Object.prototype in its prototype chain.

class Hash extends null {}
var o = {};
var hash = new Hash;
o["foo"] = 5;
hash["foo"] = 5;
// both are used as hash maps (or use `Map`).
hash["toString"]; // undefined
o["toString"]; // function

As we know, undefined in fact is not a function. In this case we can create objects without fearing a call on a field that shouldn't be there.

This is a common pattern through Object.create(null) and is common in a lot of code bases including big ones like NodeJS.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMark AmeryView Question on Stackoverflow
Solution 1 - JavascriptBakkotView Answer on Stackoverflow
Solution 2 - JavascriptBenjamin GruenbaumView Answer on Stackoverflow