When to use prototype (JS)

Asked

Viewed 2,610 times

15

What’s the difference between:

Person.prototype.sayHello = function() {
    alert("Hello, I'm " + this.firstName);
};

and

Person.sayHello = function() {
    alert("Hello, I'm " + this.firstName);
};

?

2 answers

21


The difference is best explained with an example:

var Person = function(name) {
  this.name = name;
}

Person.sayHello = function() {
  console.log("Hello " + this.name);
}

Person.prototype.sayHi = function() {
  console.log("Hi "+ this.name);
}

var p1 = new Person("Fulano");

Person.sayHello(); // "Hello "
p1.sayHello();     // Erro: sayHello não está definido
p1.sayHi();        // "Hi Fulano"

When you add a function or attribute to the prototype, this function (or attribute) is available to all instances of the class (created with the new).

When you change without the prototype, only the object in question has the function/attribute. The instances do not have it.

Note that it is possible to define the methods directly within your class, using the this:

var Person = function(name) {
  this.name = name;
  this.sayHi = function() {
    console.log("Hi " + this.name);
  }
}

var p1 = new Person("Fulano");
p1.sayHi();        // "Hi Fulano"

As noted by @bfavaretto: "if you have multiple instances of the same object, put it in the prototype. Otherwise each object will have its own copy of the method, it is usually a waste of resources".

  • In case if I set the methods inside the object, I would not need to add to the prototype, correct?

  • If you create the methods with the this, don’t need.

  • Ahh right, got it, vlww!

  • 5

    Note (about the last part): if you have several instances of the same object, put it in the prototype. Otherwise each object will have its own copy of the method, it is usually a waste of resources.

  • Right, in this case it will be only 1 instance of the same object, because I made an object with all the functionalities, is a small site. But vlw by tip!

13

Okay, let’s make a few points...

It’s just three big cases

It all comes down to three big cases:


1: Function of the prototype

The following situation illustrates the declaration of a prototype, with a prototype function:

var Person = function(firstName){
    if(!firstName) this.firstName = "Fulano";
    else this.firstName = firstName;
}
Person.prototype.sayHello = function(){ alert("Hi, I'm " + this.firstName); };

Any object declared from this prototype (var a = new Person();) will have access to the function. Even if we performed our instance before the function declaration itself, it would still have access as soon as the function was declared:

var Person = function(firstName){
    if(!firstName) this.firstName = "Fulano";
    else this.firstName = firstName;
}
var a = new Person();

// Neste trecho, 'a' ainda não conhece a função, e uma chamada resultaria
// em um erro de execução.

Person.prototype.sayHello = function(){ alert("Hi, I'm " + this.firstName); };

// Já neste trecho, 'a' já conhece a função e poderia chamá-la.

2: Function of the instance

Prototype instances, being objects, can contain attributes and methods. What do you think that this ago?

// ...
if(!firstName) this.firstName = "Fulano";
else this.firstName = firstName;
// ...

Each instance, if you specify a parameter firstName call to function Person, will receive its own attribute called... firstName!!! (But it could be another name, without changing the function parameter name!)

var Person = function(firstName){
    if(!firstName) this.nome = "Fulano";
    else this.nome = firstName;
}

In summary: the this declare, within the object (instance), an attribute or method (as in the example below):

var Person = function(firstName){
    if(!firstName) this.firstName = "Fulano";
    else this.firstName = firstName;
    this.sayHello = function(){ alert("Hi, I'm " + this.firstName);
}

Every instance of this prototype Person leaves "factory" with its own attribute firstName and its own function sayHello(). As very well pointed out by @bfavaretto, this can mean a great waste of resources, because even identical, the functions of each object are declared independently; it is as if, behind the scenes, each instance of the prototype (var a = new Person("Rui"); var b = new Person("Ricardo");) was stated in a manner similar to that:

var c = {};
c.firstName = "Rui";
c.sayHello = function(){ alert("Hi, I'm " + this.firstName);

var d = {};
d.firstName = "Ricardo";
d.sayHello = function(){ alert("Hi, I'm " + this.firstName);

Obviously, a crucial difference from the above example for instantiation is that in no way 'c' and’d' can be considered instances of Person (c.constructor == "function Object() { [native code] }", whereas a.constructor == prototype definition Person).

However, it is quite evident at this point that each instance is "free to follow its own path", creating alternative definitions for its own function (its own sayHello() ), and thus overriding in its scope the original definition.

This being said, it is worth noting that we can take advantage of the best of both worlds: save resources, while allowing own definitions for each instance. And how is this done? Taking advantage from the fact that the instances seek, first, attributes and own methods and then the prototype:

var Person = function(firstName){
    if(!firstName) this.firstName = "Fulano";
    else this.firstName = firstName;
}
Person.prototype.sayHello = function(){ alert("Hi, I'm " + this.firstName); };
var a = new Person("Evandro");
var b = new Person("Fabrício");

// Neste trecho, 'a' e 'b' conhecem apenas a definição original da função 'sayHello()'; por sinal, as definições NÃO FORAM duplicadas para dentro de cada instância do protótipo!

a.sayHello = function(){ alert("Viva la revolucion!"); }

// 'b' procura primeiramente a função `sayHello()` dentro de si, mas não encontra e acaba executando a função do protótipo:
b.sayHello();

// Já 'a' procura a função dentro de si e **ENCONTRA**, motivo pelo qual ela executa sua própria definição "particular" ao invés da do protótipo:
a.sayHello();

3: Function function (a.k.a. "Madness? This is Javascript!")

So far, I have presented valid solutions for what you want to do. Note that I have not talked about the option:

Person.sayHello = function() {
    console.log("Hello " + this.name);
}

As amazing as it may seem to the people who are starting, in Javascript the functions are nothing more than instances of the prototype called... Function!!

var Person = function(){};
console.log(Person.constructor); // function Function() { [native code] }

So... what prevents us from declaring a function in this our (instance of) function? In fact, nothing:

var Person = function(firstName){
    if(!firstName) this.firstName = "Fulano";
    else this.firstName = firstName;
}
Person.sayHello = function() {
    alert("Hello, I'm " + this.firstName);
};
Person.sayHello(); // Hello, I'm undefined
Person.firstName = "Função";
Person.sayHello(); // Hello, I'm Função

Conclusions

  1. Use the declaration in the prototype (Person.prototype.funcao = ...) to make the function definition available for all instances; it serves for attributes.

  2. You can declare particular definitions in instances (a.funcao = ...), whenever necessary.

  3. Define functions within the prototype declaration (this.funcao = ...) may seem more elegant, but it will be a trap in most cases as it results in duplicates such as those declared in a particular way (a.funcao = ...), but with identical content, which is totally unnecessary and therefore contraindicated.

  4. Define functions in the prototype construction function (Person.funcao = ...) will generally be of no use; in terms of instances, at least, it certainly will have no effect.


Jsfiddle

I made a Jsfiddle with a series of tests; who wants to take a look, I make the link available here.

I hope I’ve helped!

  • Defining instances in the constructor is - more or less - equivalent to creating static methods.

  • 1

    Excellent answer... I’ve always been a little unsure of the difference and the third case is just love for JS

Browser other questions tagged

You are not signed in. Login or sign up in order to post.