Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ES2015 Classes prevent setting the prototype

I discovered that ES2015 classes prevent setting (redefining) their prototype.

It is often claimed that ES2015 classes are just "syntactic sugar" on top of ES5 constructor functions and prototype based inheritance.
But this is a difference in behavior...

Is this behavior part of the ES2015 specification? I did not find any documentation about this ...

The following examples illustrate the difference:

function Pet() {}
Pet.prototype.eat = () => {
  console.log('Pet is eating ...');
}

Pet.prototype = {eat: function(){console.log('Pet is REALLY eating ...')}};

const pet = new Pet();
pet.eat();     // -> Pet is REALLY eating ...

console.log(Object.getOwnPropertyDescriptor(Pet, 'prototype'));

=> Redefining prototype of Pet works

class Pet {
  eat() {
    console.log('Pet is eating ...');
  }
}


Pet.prototype = {eat: function(){console.log('Pet is REALLY eating ...')}};

const pet = new Pet();
pet.eat();     // -> Pet is eating ...

console.log(Object.getOwnPropertyDescriptor(Pet, 'prototype'));

=> Redefining prototype of Pet does not work

Any pointers to documentation of this behavior would be appreciated ...

like image 635
jbandi Avatar asked May 26 '18 14:05

jbandi


People also ask

What is the difference between __ proto __ and prototype?

The prototype property is set to function when it is declared. All the functions have a prototype property. proto property that is set to an object when it is created using a new keyword. All objects behavior newly created have proto properties.

What is the difference between class and prototype?

Prototypes vs. Classes. The most important difference between class- and prototype-based inheritance is that a class defines a type which can be instantiated at runtime, whereas a prototype is itself an object instance.

Why should we use ES6 classes?

ES6 classes are syntactic sugar for the prototypical class system we use today. They make your code more concise and self-documenting, which is reason enough to use them (in my opinion). will give you something like: var Foo = (function () { function Foo(bar) { this.

Which object in JavaScript does not have a prototype?

JavaScript has two types of objects: function object and non-function object. Conceptually, all objects have a prototype (NOT A PROTOTYPE PROPERTY).


1 Answers

The difference here is that when created with class, the prototype object is set to writable: false so that you can't replace Pet.prototype with assignment. You can see that difference in your Object.getOwnPropertyDescriptor() call when you remove strict mode.

The OP's first code example shows this:

{
  ...
  "writable": true,
  "enumerable": false,
  "configurable": false
}

The OP's second code example shows this:

{
  ...
  "writable": false,
  "enumerable": false,
  "configurable": false
}

The writable property determines whether the property Pet.prototype can be assigned a new value or not (e.g. replaced with a new object). A false value means that you cannot replace Pet.prototype using assignment. So, when your code tries to do that, it fails.

You are still free to add or remove individual properties from the prototype object, just not replace the entire object. This makes some sense to me because replacing the entire prototype object undoes the entire class definition. You could probably change the Pet.prototype object to be writable if you had a real world reason to replace it.

This is described in the ES 2015 specification. In 14.5.14 Runtime Semantics: ClassDefinitionEvaluation, at step 16, it does this:

  1. Perform MakeConstructor(F, false, proto).

That false argument is making the prototype that is created non-writable (so it can't be replaced).

And, if you then look at 9.2.8 MakeConstructor(), you see this in step 6:

Let status be DefinePropertyOrThrow(F, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: writablePrototype, [[Enumerable]]: false, [[Configurable]]: false}).

Where the writable attribute is getting the false value that was previously passed to to it.


It is often claimed that ES2015 classes are just "syntactic sugar" on top of ES5 constructor functions and prototype based inheritance. But this is a difference in behavior...

While the general operation of the methods defined in the class is pretty much the same, this other answer describes several other differences between using class versus manually assigning to the prototype: In javascript, what are the differences between a class and a constructor?

like image 114
jfriend00 Avatar answered Sep 20 '22 11:09

jfriend00