Prototype

Todas las funciones tienen una propiedad prototype que contiene inicialmente un objeto

Podemos añadir propiedades y métodos a este objeto prototype. También podemos reemplazarlo completamente por otro objeto

Al crear objetos usando una función como constructor (con new), estos objetos adquieren un enlace secreto (__proto__ en Firebug) que apunta al prototipo de esta función constructora ( "clase" ) lo que les permite acceder a sus propiedades (y métodos) como si fueran propias.

Las propiedades propias del objetos tienen prioridad sobre las propiedades del prototipo con el mismo nombre


  function Person(gender) {
    this.gender = gender;
    console.log (this.gender + ' instantiated');
  }

  var person1 = new Person('Male');
  var person2 = new Person('Female');

  >>> person1.gender === 'Male'
  true
  >>> person2.gender === 'Female'
  true

  >>> Person.prototype.type = 'Human being';

  >>> person1.type === 'Human being'
  true
  >>> person2.type === 'Human being'
  true

  person1.type = 'Super Hero';

  >>> person1.type === 'Super Hero'
  true
  >>> person2.type === 'Human being'
  true

Cadena de Prototipos

Los objetos disponen de lo que se llama la cadena de prototipos

  • Si un objeto foo no dispone de la propiedad bar al hacer foo.bar, Javascript buscará está propiedad en su prototipo (el de la función constructora que lo creó)
  • Si no lo encuentra ahí, lo buscará en el prototipo de su prototipo
  • Y asi hasta llegar al objeto de más alto nivel, el objeto Object

    cadena de prototipos


  function Person(gender) {
    this.gender = gender;
    this.shoutGender = function () {
      return this.gender.toUpperCase();
    }
  }

  Person.prototype.sayGender = function() {
    return this.gender;
  };

  var person1 = new Person('Male');

  >>> person1.sayGender() === "Male"
  true
  >>> person1.shoutGender() === "MALE"
  true

  >>> var genderTeller = person1.sayGender;

  >>> genderTeller() === "Male"
  false
  >>> genderTeller === person1.sayGender
  true
  >>> genderTeller === Person.prototype.sayGender
  true

  >>> var Obj = {gender : 'Male'}

  >>> genderTeller.call(Obj) === "Male"
  true

  >>> var person2 = new Person('Female');
  >>> Person.prototype.shoutGender = function () {
    return "From the Class, you’re " + this.gender.toUpperCase();
  }

  >>> person1.shoutGender() === "MALE"
  true
  >>> person2.shoutGender() === "FEMALE"
  true

  >>> delete person1.shoutGender
  true

  >>> person1.shoutGender() === "MALE"
  false
  >>> person2.shoutGender() === "FEMALE"
  true
  >>> person1.shoutGender() === "From the Class, you’re MALE"
  true

  >>> person1.shoutGender = function () {
  return "I'm person1 and I’m " + this.gender.toUpperCase();
  }

  >>> person1.shoutGender() === "From the Class, you’re MALE"
  false
  >>> person1.shoutGender() === "I'm person1 and I’m MALE"
  true
  >>> person2.shoutGender() === "FEMALE"
  true

El metodo hasOwnProperty()

Cuando recorremos un objeto con un for-in pasamos por:

  • Las propiedades propias del objeto
  • Todas las propiedades accesibles a través de la cadena de prototipos

Con el método hasOwnProperty() podemos diferenciar las propiedades propias del objeto de las del prototipo

  function Gadget(name, color) {
    this.name = name;
    this.color = color;
    this.someMethod = function(){return 1;}
  }

  Gadget.prototype.price = 100;
  Gadget.prototype.rating = 3;

  var newtoy = new Gadget('webcam', 'black');

  >>> for (var prop in newtoy) { console.log(prop + ' = ' +
  newtoy[prop]); }

  name = webcam
  color = black
  someMethod = function () { return 1; }
  price = 100
  rating = 3

  >>> newtoy.hasOwnProperty('name');
  true

  >>> newtoy.hasOwnProperty('price');
  false

… por tanto, para recorrer solamente las propiedades propias del objeto podemos hacer:

  >>> for (var prop in newtoy) {
  if (newtoy.hasOwnProperty(prop))
  console.log(prop + ' = ' + newtoy[prop]);
  }

  name = webcam
  color = black
  someMethod = function () { return 1; }

El metodo isPrototypeOf()

Cada objeto dispone del método isPrototypeOf() que nos dice si un objeto en cuestión se está utilizando como prototipo de otro objeto

  var monkey = {
    hair: true,
    feeds: 'bananas',
    breathes: 'air'
  };

  function Human(name) {
    this.name = name;
  }

  Human.prototype = monkey;

  >>> var george = new Human('George');
  >>> monkey.isPrototypeOf(george)
  true

La propiedad constructor

El constructor del objeto prototype de una función constructora (clase), apunta a la función constructora

  >>> function Dog(){this.tail = true;}

  >>>> Dog.prototype.constructor === Dog
  true

  >>>> Dog.prototype
  Dog {}

  >>> var myDog = new Dog()
  >>> myDog.__proto__
  Dog {}
  >>> myDog.__proto__.constructor === Dog
  true

Sustituyendo completamente el prototype

La cadena de prototipos es dinámica excepto cuando sustituimos completamente el objeto prototype

  >>> function Dog(){this.tail = true;}
  >>> var benji = new Dog();
  >>> var rusty = new Dog();

  >>> typeof(benji.say) === "function"
  false

  >>> Dog.prototype.say = function(){return 'Woof!';}

  >>> typeof(benji.say) === "function"
  true

  >>> benji.constructor === Dog
  true
  >>> typeof(benji.constructor.prototype.say) === "function"
  true
  >>> benji.constructor.prototype.tail === undefined
  true

Si reescribimos el prototype con otro objeto perdemos la “dinamicidad” del prototipo…

  >>> Dog.prototype = {paws:4, hair:true};

  >>> benji.paws === undefined //old instance cannot locate new prototype
  True
  >>> typeof(benji.say) === "function" //but still can access old prototype
  true

  >>> var lucy = new Dog()

  >>> lucy.paws !== undefined //new instance can locate new prototype
  true
  >>> lucy.say !== undefined  //but cannot access old prototype
  false

  >>> lucy.constructor === Object
  true
  >>> benji.constructor === Dog
  true

…pero hay un comportamiento extraño

>>> lucy.constructor.prototype.paws === undefined // doesn’t exist?
true
>>> benji.constructor.prototype.paws === undefined // and here it does?
false

Si hubiéramos hecho

>>> Dog.prototype = {paws:4, hair:true};
>>> Dog.prototype.constructor = Dog;

…tendríamos lo que se espera

>>> lucy.constructor.prototype.paws === undefined // does exist!
false
>>> benji.constructor.prototype.paws === undefined // and here not!
true

Por tanto, siempre que sustituyamos completamente el prototype por otro objeto, conviene restituir el constructor de ese prototype

results matching ""

    No results matching ""