How does the prototype of an object work?

5

How do you USE the prototype of an object to be used in others?:

Having this prototype:

Estadio.prototype {

    Utilidad: 'Fútbol',
    PastoSintetico: true

}

My problems are:

  

1) Does common ownership and method refer to what everyone will have, for   Should I just specify them in prototype ?

     

2) How could I create 2 objects with these properties in common and   also with its own properties and methods?

My attempt was :

function Estadio1(nombre, capacidad) {

    this.nombre = nombre;
    this.capacidad = capacidad;

}

function Estadio2(nombre, capacidad) {

    this.nombre = nombre;
    this.capacidad = capacidad;

}

3) When creating these 3 new objects, and I want to use all their properties including obviously those of the prototype, is it only to call the object created with prototype ?, that is, this, according to my understanding:

Estadio1.prototype.utilidad

or

Estadio1.utilidad
  

4) Can you add properties to the prototypes?

     

5) Any more ways to create prototypes?

    
asked by Eduardo Sebastian 09.05.2017 в 14:54
source

2 answers

2

It seems to me that you are thinking Javascript as a language oriented objects according to the class paradigm. This is not the case. In Javascript there are no classes. Everything is an object, which is like a map (or if you come from Python, a dictionary ) of properties with their values.

var objeto1 = {nombre : 'yo', edad : 30};
var objeto2 = {nombre : 'ella', edad : 29};

function imprimirObjeto(o) {
  console.log(o);
}

imprimirObjeto(objeto1);

What you need to do is:

  • Everything object has a hidden property (the "prototype"). When I try to read a property in an object and it does not, it tries to read it in the "prototype". (The prototype can also have another prototype, and so ...)

  • The prototype can not be accessed directly.

  • A function is also an object (with a special prototype, but that does not matter for now).

  • There are functions that are designed to work as something-so-like "builders." They usually start (by convention) with a capital letter, and are not usually explicitly invoked as other functions, but only with the keyword new .

When executing

   function Casa() {
       this.habitaciones = 2;
       ...
   }
   var c1 = new Casa();
   var c2 = new Casa();

Javascript manufactures two new objects stored in variable c1 and c2 . Informally, we think that "we instantiate two houses"; correct, but do not confuse the object Casa (the constructor function, which is only one) with the objects c1 and c2 that are two objects created by Casa() and that no are copies of Casa ).

(Maybe it helps a bit to understand it if we mentally rename Casa() to fabricarCasa() , and instead of c1 = new Casa() we imagine c1 = fabricarCasa() This is how we would do it in other languages, but in Javascript it is not possible, and it's important not to get confused: you have to use new for a construction function to work as such, and if we forget, we'll see ugly things happen.

What is particular about this is that

  • The keyword this in a "constructor" will refer to the new object created in the call with new

  • A constructor has a special attribute called prototype (by default, an empty object); the value of this prototype will be assigned as a prototype of each new created object.

Eye! (And this is what is often very confusing at first): Casa.prototype is not the prototype of the object Casa ! It is the prototype that will be assigned (not by copy, but by reference) to the objects created by the function Casa !

  • The prototype of a constructor is any object, and I can modify it when I want. The change will impact (dynamically) on the objects created by the constructor (before and after the modification)

Let's see if with an example it is understood (execute and look at the console).

// esta es un funcion que se usará como constructor
function Estadio(nombre, capacidad) {
    this.nombre = nombre;
    this.capacidad = capacidad;
}

// modificamos directamente el objeto prototype de la funcion constructora , agregando un atributo 
// notar que Estadio.prototype no es el prototipo de Estadio
Estadio.prototype.utilidad = 'x'; 

// creamos dos objetos
// estos objetos tendran como prototipo (oculto) el objeto (unico) Estadio.prototype
var estadio1 = new Estadio('Estadio 1',20);
var estadio2 = new Estadio('Estadio 2',30);

console.log("Nombre de estadio 1:" + estadio1.nombre);
console.log("Nombre de estadio 2:" + estadio2.nombre);

// estas propiedades no estan en cada objeto, pero sí en el prototipo
console.log("Utilidad de estadio 1:" + estadio1.utilidad);
console.log("Utilidad de estadio 2:" + estadio2.utilidad);

// cambiamos el atributo prototype de la funcion Estadio
// (que a su vez está refernciado en el prototipo oculto 
//de los dos objetos anteriores
Estadio.prototype.utilidad = 'y';

// vemos que ese cambio "lo ven" los objetos
console.log("Utilidad de estadio 1:" + estadio1.utilidad);
console.log("Utilidad de estadio 2:" + estadio2.utilidad);

// como el atributo no estaba en el objeto (sino en el prototipo), se crea 
// en el objeto (la cadena de prototipos se usa para leer, nunca se escribe)
estadio1.utilidad = 'y1';
// ver que ahora los objetos ven diferentes atributos
console.log("Utilidad de estadio 1:" + estadio1.utilidad);
console.log("Utilidad de estadio 2:" + estadio2.utilidad);

// moficiamos nuevamente el prototipo "global"
Estadio.prototype.utilidad = 'z';
// eso solo incide en el segundo objeto, porque el primero lo tiene 
console.log("Utilidad de estadio 1:" + estadio1.utilidad);
console.log("Utilidad de estadio 2:" + estadio2.utilidad);

Regarding "create objects with common properties". You have to distinguish: do you want all of them to have the same set of properties (but perhaps with different values) or do you want them to share the values?

Usually the constructor (as in my examples and yours) define a set of properties with their values. Each object created by that constructor will have those properties with (a copy of) those values, which eventually we can change. We could achieve something similar by assigning those properties to a prototype.

Specifically, compare

 function Casa() {
       this.habitaciones = 2;
 }
 var c1 = new Casa();
 var c2 = new Casa();

with

 function Casa() {
 }
 Casa.prototype.habitaciones = 2;
 var c1 = new Casa();
 var c2 = new Casa();

The result will be almost indistinguishable, both to read c1.habitaciones and to write it.

The advantage of the second (attributes in the prototype) is that it is more efficient in memory management, because if I create 10 objects I do not have 10 copies of the attribute habitaciones but (as long as it does not change it) only one, the one that lives in the prototype. This efficiency is VERY important in some Javascript applications, in particular to manage the DOM (object tree of a web page) and events.

Another difference is that the second procedure is more flexible because if, once the 10 objects are created, I modify the prototype, the 10 objects (as long as they do not write it) will see the attribute reflected. Of course this, in some cases, can be a disadvantage.

    
answered by 09.05.2017 / 21:10
source
4

First of all you must know what the prototype of an object consists of in JavaScript . JavaScript is a language based on prototyping , the objects instead of extending from a higher class, what they do is share the same properties contained in the prototype of the main object that is instantiated.

In summary:

  

The prototype of an object is the one that contains all the properties that the instances of that object will inherit.

To give you a practical example, look at the following code:

function Animal (nombre) {
  this.nombre = nombre;
}

Animal.prototype.camina = function () {
  console.log(this.nombre + " a echado a andar");
}

var animal1 = new Animal("conejo");
var animal2 = new Animal("caballo");

animal1.camina();
animal2.camina();

As you can see, animal1 and animal2 are instances of the object Animal , each one has a property nombre , which is different in each of the two. However, both share the same method caminar , what it does is launch in the console a message that contains the property nombre of each instance.

I think the previous snippet answers most of your questions. Now, regarding the question in which you want to know if you can add properties to the prototypes, the answer is yes, you can add properties although I particularly do not like that idea, I prefer to leave the prototype only for methods. When I want to create public properties I usually use Object.defineProperty (if the code needs to be executed at least in Internet Explorer 9 ):

function Animal (nombre) {
  this.nombre = nombre;
}

Object.defineProperty(Animal.prototype, "name", {
  get: function () {
    return this.nombre.toUpperCase();
  }
});

var animal1 = new Animal("conejo");
var animal2 = new Animal("caballo");

console.log( animal1.name );
console.log( animal2.name );

Regarding the question of whether there is another way to create prototypes, ECMAScript 2015 introduces a new form, using the declaration class . It is not a true class, at the end JavaScript internally will understand this as an object with methods added to its prototype, but it is a much clearer and simple syntax:

class Animal {

  constructor (nombre) {
    this.nombre = nombre;
  }

  camina () {
    console.log('${this.nombre} a echado a andar');
  }

}

var animal1 = new Animal("conejo");
var animal2 = new Animal("caballo");

animal1.camina();
animal2.camina();

EDITING:

Maybe you need at a certain moment to create instances of an object that extends from another object and as JavaScript is not a language based on classes you have to use other techniques (basically replace the prototype of the object with the object of the that will extend and then define the constructor of the new object so that it is not the one of the object of the one that inherits):

//---Animal
function Animal (nombre) {
  this.nombre = nombre;
}

Animal.prototype.getNombre = function () {
  console.log("el nombre del animal es " + this.nombre);
};

//---Mamífero
function Mamifero (nombre) {

  Animal.apply(this, arguments);
  
  this.respira = function () {
    console.log(this.nombre + " ha comenzado a respirar");
  };
  
}

Mamifero.prototype = Object.create(Animal.prototype);
Mamifero.constructor = Mamifero;

//---Reptil
function Reptil (nombre) {

  Animal.apply(this, arguments);
  
  this.repta = function () {
    console.log(this.nombre + " a comenzado a reptar");
  };
  
}

Reptil.prototype = Object.create(Animal.prototype);
Reptil.constructor = Reptil;


//---Instancias
var conejo = new Mamifero("conejo");
conejo.getNombre();
conejo.respira();

var lagarto = new Reptil("lagarto");
lagarto.getNombre();
lagarto.repta();

The previous code becomes infinitely more readable and compact in ECMAScript 2015 :

//---Animal
class Animal {

  constructor (nombre) {  
    this.nombre = nombre;  
  }
  
  getNombre () {  
    console.log('el nombre del animal es ${this.nombre}');  
  }
  
}

//---Mamífero
class Mamifero extends Animal {

  respira () {
    console.log('${this.nombre} ha comenzado a respirar');
  }

}

//---Reptil
class Reptil extends Animal {

  repta () {
    console.log('${this.nombre} a comenzado a reptar');
  }

}

//---Instancias
var conejo = new Mamifero("conejo");
conejo.getNombre();
conejo.respira();

var lagarto = new Reptil("lagarto");
lagarto.getNombre();
lagarto.repta();
    
answered by 09.05.2017 в 21:08