Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do we still need prototype in ES6 to have one copy of a method shared across all class instances?

Update 2: This question is a mess, because I thought the ES6 class doesn't modify .protototype, which it does, and hence this is exactly what I wanted.

I accepted the broadest answer even if all the answers and comments should have pointed me to the right direction in the very beginning :)

Thank you all!

Old:

In old JS, pre ES6, when we learned about making "classes" with:

function X() {
    this.foo = function(){
    }
}; 
var x = new X();

we also knew that every time we do x = new X(); we get a copy of the 'foo' method, in every instance This was one of the reasons why using prototype was a good idea.

Now, in ES6 we have this new cool class syntax, but with the same 'issue', i.e. here the 'f' method is copied. How do we avoid it in a ES6 way? Or do we still need to use .prototype?

class X{
  f(){
    return 'f';
  }
}

console.clear();
let x1 = new X();
let x2 = new X();
x2.f = function() {return 'changed f';};

console.log(x1.f());//f
console.log(x2.f());//changed f

Update

I do understand we can still use .prototype. My question was more about using a more modern way to achieve what I wanted, i.e. not having copies of methods. I checked the very first tutorial about JS prototypes to find a citation, if my English is that bad :) - Found on https://hackernoon.com/prototypes-in-javascript-5bba2990e04b :

(...) i.e. every object created using the constructor function will have it’s own copy of properties and methods. It doesn’t make sense to have two instances of function fullName that do the same thing. Storing separate instances of function for each objects results into wastage of memory. We will see as we move forward how we can solve this issue.

And you also mentioned that class ... is only a syntactic sugar, but then why... with function FC below, we can see can see the "f" method directly in fc1, and

function FC() {
    this.v = 42;
    this.f = function(){
    }
}; 

var fc1 = new FC();

console.log('fc1, we can see the "f" directly in fc1: ', 
    Object.getOwnPropertyNames(fc1)
);


//////////////////////////////////

class X{
  constructor(){
    this.v  = 'bar';
  }
  f(){
    return 'f';
  }
}


let x1 = new X();

console.log('x1, we don\'t, because we have it in prototype:',
    Object.getOwnPropertyNames(x1)
);
like image 488
konrados Avatar asked Apr 24 '18 02:04

konrados


People also ask

Do we still use prototype in JavaScript?

A prototype is an existing inbuilt functionality in JavaScript. Whenever we create a JavaScript function, JavaScript adds a prototype property to that function. A prototype is an object, where it can add new variables and methods to the existing object.

Does ES6 use prototype?

Yes, ES6 class methods are defined within the object prototype.

Do all objects have prototypes in JavaScript?

Each and every JavaScript function will have a prototype property which is of the object type. You can define your own properties under prototype . When you will use the function as a constructor function, all the instances of it will inherit properties from the prototype object.


1 Answers

ES6 classes are syntactic sugar for established inheritance pattern that have been used in ES5.

ES6 classes use prototype methods by design. A method is shared among instances, so it's reasonable to define it once on prototype object and prototypically inherit it in instances. Prototypes are consistently optimized in modern engines and show performance benefits in some cases, so they can be preferred where appropriate.

My question was more about using a more modern way to achieve what I wanted, i.e. not having copies of methods.

Memory footprint can be reduced by reusing a function. This isn't a 'modern' way, just a way to address the issue:

function function f(){}
function FC() {
    this.v = 42;
    this.f = f;
};

A 'modern' way is to use prototype members.

FC function is not a direct counterpart to X class because the former assigns f on instance, not constructor prototype. A direct counterpart (with the exception of f descriptor, which is also non-enumerable in ES6 class) would be:

function FC() {
    this.v = 42;
}; 
FC.prototype.f = function(){};

class X{
  constructor(){
    this.v  = 'bar';
  }
  f(){}
}
// typeof X.prototype.f === 'function'

The reason why this style wasn't used consistently in ES5 is because this.f takes less characters to type and may be more readable than FC.prototype.f, while a developer may be unaware of the benefits and quirks of prototype.

The promotion of prototype members (methods and getters/setters) is one of few problems that class syntactic sugar addresses.

like image 88
Estus Flask Avatar answered Sep 20 '22 23:09

Estus Flask