When using prototype (JS)

13

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);
};

?

    
asked by anonymous 21.08.2014 / 20:35

2 answers

18

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

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

Note that you can define 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 it in prototype, otherwise each object will have its own copy of the method, usually a waste of resources."

    
21.08.2014 / 20:46
10

Okay, let's go to some points ...

There are only three major 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 ran 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: 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 firstName parameter when calling the Person function, will get its own attribute called ... firstName !!! (But it could be another name, without changing the parameter name of the function!)

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

In summary: this will declare a 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 Person prototype exits "factory" with its own firstName attribute and its own sayHello() function. As 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 cloths, each instance of the prototype ( var a = new Person("Rui"); var b = new Person("Ricardo"); ) was declared in a similar way as 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 example above for instantiation is that in any way 'c' and 'd' can be considered instances of Person ( c.constructor == "function Object() { [native code] }" , while 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%), and thereby nullifying in its scope the original definition.

That said, it is worth emphasizing that we can take advantage of the best of both worlds: saving resources, while allowing proper definitions for each instance. And how is this done? Getting advantage from the fact that instances first look for attributes and methods of their own and then 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. Note that I did not mention the option:

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

As incredible as it may seem to the people who are just starting out, 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 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

  • Use the declaration in the prototype ( sayHello() ) to make the function definition available to all instances; the same goes for attributes.

  • You can declare particular definitions in instances ( Person.prototype.funcao = ... ) whenever necessary.

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

  • Defining functions in the constructor function of the prototype ( a.funcao = ... ) will generally be useless; in terms of instances, at least it certainly does not have any effect.

  • JSFiddle

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

    I hope I have helped!

        
    21.08.2014 / 23:41