When to use prototype (JS)

What is the difference between:

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

And

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

?

 15
Author: helderburato, 2014-08-21

2 answers

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 any function or attribute to the prototype, this function (or attribute) becomes available to all instances of the class (created with new).

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

Note that you can define the methods directly within your class, using 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, better put in prototype. Otherwise each object will have its own copy of the method, it is usually a waste of resources."

 21
Author: Beterraba, 2014-08-21 19:19:19

Okay, let's go to a few points...

Are just three big cases

It all comes down to three big cases:


1: prototype function

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 then 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: instance function

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

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

Each instance, if you specify a parameter firstName when calling the function Person, will receive its own called Attribute... 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 short: the this it will 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);
}

Each 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, since even identical, the functions of each object are declared independently; it is as if, behind the cloths, each instance of the prototype (var a = new Person("Rui"); var b = new Person("Ricardo");) were declared in a manner similar to this:

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 can' c 'and' d ' be considered instances of Person (c.constructor == "function Object() { [native code] }", whereas a.constructor == definition of the prototype Person).

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

This being said, it is worth noting that we can take advantage of the best of both worlds: saving resources, while allowing own definitions for each instance. And how is this done? Taking advantage of the fact that instances first look for attributes and methods of their own and then those of 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 of the function (a. k. a. " Madness? This is JavaScript!")

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

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

As amazing as it may seem to the people starting out, in JavaScript functions are nothing more than instances of the prototype called... function !!

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

Then... what prevents us from declaring a function in this our (instance of) function? actually, 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; the same is for attributes.

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

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

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


JSFiddle

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

Hope I helped!

 13
Author: Rui Pimentel, 2014-08-21 21:41:51