Está bien, vamos a jugar un poco de juego de la mente:
Partiendo de esta imagen podemos ver:
- Cuando creamos una función como
function Foo() {}
, JavaScript crea una instancia Function
.
- Cada instancia de
Function
(la función constructora) tiene una propiedad prototype
que es un puntero.
- La propiedad
prototype
de la función constructora apunta a su objeto prototipo.
- El objeto prototipo tiene una propiedad
constructor
que también es un puntero.
- La propiedad
constructor
del objeto prototipo apunta a su función constructora.
- Cuando creamos una nueva instancia de
Foo
como new Foo()
, JavaScript crea un nuevo objeto.
- La propiedad interna
[[proto]]
de la instancia apunta al prototipo del constructor.
Ahora, surge la pregunta de por qué JavaScript no asocia la propiedad constructor
al objeto de instancia en lugar del prototipo. Considere:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
var Square = defclass({
constructor: function (side) {
this.side = side;
},
area: function() {
return this.side * this.side;
}
});
var square = new Square(10);
alert(square.area()); // 100
Como se puede ver la propiedad constructor
es sólo otro método del prototipo, como area
en el ejemplo anterior. Lo que hace especial a la propiedad constructor
es que se usa para inicializar una instancia del prototipo. De lo contrario, es exactamente lo mismo que cualquier otro método del prototipo.
Definición de la propiedad constructor
en el prototipo es ventajoso por las siguientes razones:
- Es lógicamente correcto. Por ejemplo, considere
Object.prototype
. La propiedad constructor
de Object.prototype
apunta a Object
. Si la propiedad constructor
se definió en la instancia, entonces Object.prototype.constructor
sería undefined
porque Object.prototype
es una instancia de null
.
- No se trata de manera diferente a otros métodos de prototipos. Esto facilita el trabajo de
new
ya que no necesita definir la propiedad constructor
en cada instancia.
- Cada instancia comparte la misma propiedad
constructor
. Por lo tanto, es eficiente.
Ahora bien, cuando hablamos de herencia, tenemos el siguiente escenario:
Partiendo de esta imagen podemos ver:
- propiedad del constructor derivado
prototype
se establece en la instancia del constructor base.
- Por lo tanto, la propiedad
[[proto]]
interna de la instancia del constructor derivado también lo señala.
- Por lo tanto, la propiedad
constructor
de la instancia del constructor derivado apunta ahora al constructor base.
En cuanto a la instanceof
operador, contrariamente a la creencia popular que no depende de la propiedad constructor
de la instancia. Como podemos ver desde arriba, eso llevaría a resultados erróneos. El operador instanceof
es un operador binario (tiene dos operandos). Opera en un objeto de instancia y una función de constructor. Como se explicará en Mozilla Developer Network, simplemente hace lo siguiente:
function instanceOf(object, constructor) {
while (object != null) {
if (object == constructor.prototype) { //object is instanceof constructor
return true;
} else if (typeof object == 'xml') { //workaround for XML objects
return constructor.prototype == XML.prototype;
}
object = object.__proto__; //traverse the prototype chain
}
return false; //object is not instanceof constructor
}
En pocas palabras, si Foo
hereda de Bar
, a continuación, la cadena de prototipo para la instancia de Foo
sería:
foo.__proto__ === Foo.prototype
foo.__proto__.__proto__ === Bar.prototype
foo.__proto__.__proto__.__proto__ === Object.prototype
foo.__proto__.__proto__.__proto__.__proto__ === null
Como puede ver, cada objeto hereda del constructor Object
. La cadena del prototipo finaliza cuando una propiedad interna [[proto]]
apunta a null
.
La función instanceof
simplemente atraviesa la cadena de prototipo del objeto de instancia (el primer operando) y compara la [[proto]]
propiedad interna de cada objeto a la propiedad prototype
de la función de constructor (el segundo operando). Si coinciden, devuelve true
; y si la cadena del prototipo termina, devuelve false
.
¿Alguna razón por la que necesita que se actualice el constructor? Encuentro que mi vida es más fácil si solo pretendo que la propiedad no existe. – hugomg
Me está resultando difícil cerrar esto como un duplicado - todos los otros questinos son tan detallados ... – hugomg
'c.prototype' es' b() 'y' b.prototype' es 'a()', por lo tanto 'c.prototype' es' a() ' –