objetos herencia clases javascript dynamic-languages prototype-oriented

herencia - ¿Cómo funciona JavaScript.prototype?



objetos javascript (23)

No estoy tan dentro de los lenguajes de programación dinámica, pero he escrito mi parte justa de código JavaScript. Realmente nunca entendí esta programación basada en prototipos, ¿alguien sabe cómo funciona esto?

var obj = new Object(); obj.prototype.test = function() { alert(''Hello?''); }; var obj2 = new obj(); obj2.test();

Recuerdo mucho la discusión que tuve con la gente hace un tiempo (no estoy muy seguro de lo que estoy haciendo) pero como lo entiendo, no hay concepto de una clase. Es solo un objeto, y las instancias de esos objetos son clones del original, ¿verdad?

¿Pero cuál es el propósito exacto de esta propiedad ".prototype" en JavaScript? ¿Cómo se relaciona con la instanciación de objetos?

Actualización: forma correcta

var obj = new Object(); // not a functional object obj.prototype.test = function() { alert(''Hello?''); }; // this is wrong! function MyObject() {} // a first class functional object MyObject.prototype.test = function() { alert(''OK''); } // OK

También estas slides realmente ayudaron mucho.


¿Cuál es el propósito exacto de esta propiedad ".prototype"?

La interfaz a clases estándar se vuelve extensible. Por ejemplo, está utilizando la Arrayclase y también necesita agregar un serializador personalizado para todos sus objetos de matriz. ¿Pasaría tiempo codificando una subclase, o usaría la composición o ... La propiedad prototipo resuelve esto al permitir que los usuarios controlen el conjunto exacto de miembros / métodos disponibles para una clase?

Piense en los prototipos como un puntero vtable adicional. Cuando faltan algunos miembros de la clase original, se busca el prototipo en tiempo de ejecución.


Los siete Koans del prototipo.

Cuando Ciro San descendió de Mount Fire Fox después de una profunda meditación, su mente era clara y pacífica.

Su mano, sin embargo, estaba inquieta, y por sí misma tomó un cepillo y anotó las siguientes notas.

0) Dos cosas diferentes se pueden llamar "prototipo":

  • la propiedad prototipo, como en obj.prototype

  • la propiedad interna del prototipo, denotada como [[Prototype]] en ES5 .

    Se puede recuperar a través del Object.getPrototypeOf() ES5.

    Firefox lo hace accesible a través de la propiedad __proto__ como una extensión. ES6 ahora menciona algunos requisitos opcionales para __proto__ .

1) Esos conceptos existen para responder a la pregunta:

Cuando hago obj.property , ¿dónde busca JS para .property ?

Intuitivamente, la herencia clásica debería afectar la búsqueda de propiedades.

2)

  • __proto__ se usa para el punto . búsqueda de propiedades como en obj.property .
  • .prototype no se usa para buscar directamente, solo indirectamente, ya que determina __proto__ en la creación de objetos con new .

El orden de búsqueda es:

  • propiedades obj agregadas con obj.p = ... o Object.defineProperty(obj, ...)
  • propiedades de obj.__proto__
  • propiedades de obj.__proto__.__proto__ , y así sucesivamente
  • si algún __proto__ es null , devuélvalo undefined .

Esta es la llamada cadena prototipo .

Usted puede evitar . búsqueda con obj.hasOwnProperty(''key'') y Object.getOwnPropertyNames(f)

3) Hay dos formas principales de establecer obj.__proto__ :

  • new :

    var F = function() {} var f = new F()

    entonces new ha establecido:

    f.__proto__ === F.prototype

    Aquí es donde se usa el .prototype .

  • Object.create :

    f = Object.create(proto)

    conjuntos:

    f.__proto__ === proto

4) El código:

var F = function() {} var f = new F()

Corresponde al siguiente diagrama:

(Function) ( F ) (f) | ^ | | ^ | | | | | | | | | | | +-------------------------+ | | |constructor | | | | | | | +--------------+ | | | | | | | | | | | | | | |[[Prototype]] |[[Prototype]] |prototype |constructor |[[Prototype]] | | | | | | | | | | | | | | | | +----------+ | | | | | | | | | | | | +-----------------------+ | | | | | | v | v v | v (Function.prototype) (F.prototype) | | | | |[[Prototype]] |[[Prototype]] | | | | | +-------------------------------+ | | v v (Object.prototype) | | ^ | | | | | +---------------------------+ | | | | +--------------+ | | | | | | | |[[Prototype]] |constructor |prototype | | | | | | | | -------------+ | | | v v | (null) (Object)

Este diagrama muestra muchos nodos de objetos predefinidos de lenguaje: null , Object , Object.prototype , Function y Object.prototype . Nuestras 2 líneas de código solo crearon f , F y F.prototype .

5) .constructor normalmente proviene de F.prototype través de . buscar:

f.constructor === F !f.hasOwnProperty(''constructor'') Object.getPrototypeOf(f) === F.prototype F.prototype.hasOwnProperty(''constructor'') F.prototype.constructor === f.constructor

Cuando escribimos f.constructor , JavaScript hace el . búsqueda como

  • f no tiene .constructor
  • f.__proto__ === F.prototype tiene .constructor === F , así que .constructor === F

El resultado f.constructor == F es intuitivamente correcto, ya que F se usa para construir f , por ejemplo, establecer campos, como en los lenguajes clásicos OOP.

6) La sintaxis de herencia clásica se puede lograr mediante la manipulación de cadenas de prototipos.

ES6 agrega la class y extends palabras clave, que son simplemente sintaxis de azúcar para la posible locura de manipulación de prototipos.

class C { constructor(i) { this.i = i } inc() { return this.i + 1 } } class D extends C { constructor(i) { super(i) } inc2() { return this.i + 2 } }

// Inheritance syntax works as expected. (new C(1)).inc() === 2 (new D(1)).inc() === 2 (new D(1)).inc2() === 3

// "Classes" are just function objects. C.constructor === Function C.__proto__ === Function.prototype D.constructor === Function // D is a function "indirectly" through the chain. D.__proto__ === C D.__proto__.__proto__ === Function.prototype

// "extends" sets up the prototype chain so that base class // lookups will work as expected var d = new D(1) d.__proto__ === D.prototype D.prototype.__proto__ === C.prototype // This is what `d.inc` actually does. d.__proto__.__proto__.inc === C.prototype.inc

// Class variables // No ES6 syntax sugar apparently: // http://.com/questions/22528967/es6-class-variable-alternatives C.c = 1 C.c === 1 // Because `D.__proto__ === C`. D.c === 1 // Nothing makes this work. d.c === undefined

Diagrama simplificado sin todos los objetos predefinidos:

__proto__ (C)<---------------(D) (d) | | | | | | | | | |prototype |prototype |__proto__ | | | | | | | | | | | +---------+ | | | | | | | | | | v v |__proto__ (D.prototype) | | | | | | | | |__proto__ | | | | | | | | +--------------+ | | | | | | | v v | (C.prototype)--->(inc) | v Function.prototype


Resumen:

  • Las funciones son objetos en javascript y por lo tanto pueden tener propiedades.
  • Las funciones (constructoras) siempre tienen una propiedad prototipo.
  • Cuando se utiliza una función como constructor con la newpalabra clave, el objeto obtiene una __proto__propiedad
  • Esta __proto__propiedad se refiere a la prototypepropiedad de la función constructora.

Ejemplo:

function Person (name) { this.name = name; } let me = new Person(''willem''); console.log(Person.prototype) // Person has a prototype property console.log(Person.prototype === me.__proto__) // the __proto__ property of the instance refers to prototype property of the function.

¿Por qué es útil esto?

Javascript tiene un mecanismo al buscar propiedades en Objetos que se llama ''herencia prototípica'' , aquí está lo que básicamente hace:

  • Primero se comprueba si la propiedad se encuentra en el objeto en sí. Si es así se devuelve esta propiedad.
  • Si la propiedad no se encuentra en el objeto en sí, "escalará la protocta". Básicamente mira el objeto referido por la propiedad proto . Allí verifica si la propiedad está disponible en el objeto referido por proto
  • Si la propiedad no está ubicada en el objeto proto , subirá la cadena de proto hasta el objeto Objeto.
  • Si no puede encontrar la propiedad en ninguna parte del objeto y su cadena de prototipo, se devolverá indefinido.

Por ejemplo:

function Person(name) { this.name = name; } let mySelf = new Person(''Willem''); console.log(mySelf.__proto__ === Person.prototype); console.log(mySelf.__proto__.__proto__ === Object.prototype);


Cada objeto de JavaScript tiene una propiedad interna llamada [[Prototipo]] . Si busca una propiedad a través de obj.propName u obj[''propName''] y el objeto no tiene dicha propiedad, que se puede verificar a través de obj.hasOwnProperty(''propName'') , el tiempo de ejecución busca la propiedad en el objeto referenciado por [[Prototipo]] en su lugar. Si el objeto prototipo tampoco tiene dicha propiedad, su prototipo se verifica a su vez, por lo que se recorre la cadena de prototipo del objeto original hasta que se encuentra una coincidencia o se alcanza su final.

Algunas implementaciones de JavaScript permiten el acceso directo a la propiedad [[Prototype]], por ejemplo, a través de una propiedad no estándar llamada __proto__ . En general, solo es posible configurar el prototipo de un objeto durante la creación del objeto: si crea un nuevo objeto a través de la new Func() , la propiedad [[Prototype]] del objeto se establecerá en el objeto referenciado por Func.prototype .

Esto permite simular clases en JavaScript, aunque el sistema de herencia de JavaScript es, como hemos visto, prototípico y no basado en clases:

Simplemente piense en las funciones del constructor como clases y las propiedades del prototipo (es decir, en el objeto referenciado por la propiedad del prototype la función del constructor) como miembros compartidos, es decir, miembros que son los mismos para cada instancia. En los sistemas basados ​​en clases, los métodos se implementan de la misma manera para cada instancia, por lo que los métodos normalmente se agregan al prototipo, mientras que los campos de un objeto son específicos de la instancia y, por lo tanto, se agregan al objeto en sí durante la construcción.


Cada objeto tiene una propiedad interna, [[Prototipo]], que lo vincula a otro objeto:

object [[Prototype]] -> anotherObject

En javascript tradicional, el objeto vinculado es la propiedad prototype de una función:

object [[Prototype]] -> aFunction.prototype

Algunos entornos exponen [[Prototype]] como __proto__ :

anObject.__proto__ === anotherObject

Usted crea el enlace [[Prototipo]] al crear un objeto.

// (1) Object.create: var object = Object.create(anotherObject) // object.__proto__ = anotherObject // (2) ES6 object initializer: var object = { __proto__: anotherObject }; // object.__proto__ = anotherObject // (3) Traditional JavaScript: var object = new aFunction; // object.__proto__ = aFunction.prototype

Así que estas declaraciones son equivalentes:

var object = Object.create(Object.prototype); var object = { __proto__: Object.prototype }; // ES6 only var object = new Object;

Una new declaración no muestra el objetivo del enlace ( Object.prototype ); en cambio, el objetivo está implícito por el constructor ( Object ).

Recuerda:

  • Cada objeto tiene un enlace, [[Prototipo]], a veces expuesto como __proto__ .
  • Cada función tiene una propiedad prototype .
  • Los objetos creados con new están vinculados a la propiedad prototype de su constructor.
  • Si una función nunca se usa como un constructor, su propiedad prototype no se usará.
  • Si no necesita un constructor, use Object.create lugar de new .

Después de leer este hilo, me siento confundido con JavaScript Prototype Chain, luego encontré estos gráficos

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance

Es un gráfico claro para mostrar la herencia de JavaScript por cadena de prototipo.

y

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

Este contiene un ejemplo con código y varios diagramas agradables.

La cadena de prototipos finalmente vuelve a caer en Object.prototype.

La cadena de prototipos puede extenderse técnicamente el tiempo que desee, estableciendo cada vez que el prototipo de la subclase es igual a un objeto de la clase principal.

Espero que también sea útil para que entiendas la cadena de prototipos de JavaScript.


En un lenguaje que implementa herencia clásica como Java, C # o C ++, comienza creando una clase, un plano para sus objetos, y luego puede crear nuevos objetos a partir de esa clase o puede extender la clase, definiendo una nueva clase que aumente la clase original

En JavaScript, primero creas un objeto (no hay concepto de clase), luego puedes aumentar tu propio objeto o crear nuevos objetos a partir de él. No es difícil, pero un poco extraño y difícil de metabolizar para alguien acostumbrado a la forma clásica.

Ejemplo:

//Define a functional object to hold persons in JavaScript var Person = function(name) { this.name = name; }; //Add dynamically to the already defined object a new getter Person.prototype.getName = function() { return this.name; }; //Create a new object of type Person var john = new Person("John"); //Try the getter alert(john.getName()); //If now I modify person, also John gets the updates Person.prototype.sayMyName = function() { alert(''Hello, my name is '' + this.getName()); }; //Call the new method on john john.sayMyName();

Hasta ahora he estado extendiendo el objeto base, ahora creo otro objeto y luego heredé de Person.

//Create a new object of type Customer by defining its constructor. It''s not //related to Person for now. var Customer = function(name) { this.name = name; }; //Now I link the objects and to do so, we link the prototype of Customer to //a new instance of Person. The prototype is the base that will be used to //construct all new instances and also, will modify dynamically all already //constructed objects because in JavaScript objects retain a pointer to the //prototype Customer.prototype = new Person(); //Now I can call the methods of Person on the Customer, let''s try, first //I need to create a Customer. var myCustomer = new Customer(''Dream Inc.''); myCustomer.sayMyName(); //If I add new methods to Person, they will be added to Customer, but if I //add new methods to Customer they won''t be added to Person. Example: Customer.prototype.setAmountDue = function(amountDue) { this.amountDue = amountDue; }; Customer.prototype.getAmountDue = function() { return this.amountDue; }; //Let''s try: myCustomer.setAmountDue(2000); alert(myCustomer.getAmountDue());

var Person = function (name) { this.name = name; }; Person.prototype.getName = function () { return this.name; }; var john = new Person("John"); alert(john.getName()); Person.prototype.sayMyName = function () { alert(''Hello, my name is '' + this.getName()); }; john.sayMyName(); var Customer = function (name) { this.name = name; }; Customer.prototype = new Person(); var myCustomer = new Customer(''Dream Inc.''); myCustomer.sayMyName(); Customer.prototype.setAmountDue = function (amountDue) { this.amountDue = amountDue; }; Customer.prototype.getAmountDue = function () { return this.amountDue; }; myCustomer.setAmountDue(2000); alert(myCustomer.getAmountDue());

Mientras que como dije no puedo llamar a setAmountDue (), getAmountDue () en una Persona.

//The following statement generates an error. john.setAmountDue(1000);


Este artículo es largo. Pero estoy seguro de que aclarará la mayoría de sus consultas con respecto a la naturaleza "prototípica" de la herencia de JavaScript. Y aún más. Por favor lea el artículo completo.

JavaScript básicamente tiene dos tipos de tipos de datos

  • No objetos
  • Objetos

No objetos

Los siguientes son los tipos de datos no objeto

  • cuerda
  • número (incluyendo NaN e Infinito)
  • valores booleanos (verdadero, falso)
  • indefinido

Estos tipos de datos devuelven lo siguiente cuando usa el operador typeof

typeof "cadena literal" (o una variable que contiene cadena literal) === ''cadena''

typeof 5 (o cualquier literal numérico o una variable que contenga literal numérico o NaN o Infynity ) === ''número''

typeof true (o false o una variable que contiene true o false ) === ''boolean''

typeof undefined (o una variable indefinida o una variable que contiene indefinida ) === ''indefinida''

La cadena , el número y los tipos de datos booleanos se pueden representar como Objetos y Objetos No. Cuando se representan como objetos, su tipo de tipo es siempre === ''objeto''. Volveremos a esto una vez que entendamos los tipos de datos del objeto.

Objetos

Los tipos de datos de los objetos se pueden dividir en dos tipos.

  1. Objetos de tipo de función
  2. Objetos de tipo no funcional

Los objetos de tipo Función son los que devuelven la cadena ''función'' con el operador typeof . Todas las funciones definidas por el usuario y todo el JavaScript integrado en los objetos que pueden crear nuevos objetos mediante el uso de un nuevo operador pertenecen a esta categoría. Por ejemplo.

  • Objeto
  • Cuerda
  • Número
  • Booleano
  • Formación
  • Matrices mecanografiadas
  • RegExp
  • Función
  • Todos los demás objetos integrados que pueden crear nuevos objetos utilizando un nuevo operador
  • función UserDefinedFunction () {/ * código definido por el usuario * /}

Entonces, typeof (Object) === typeof (String) === typeof (Number) === typeof (Boolean) === typeof (Array) === typeof (RegExp) === typeof (Function) == = typeof (UserDefinedFunction) === ''function''

Todos los objetos de tipo de función son en realidad instancias de la función de objeto JavaScript incorporada (incluido el objeto de función, es decir, se define de forma recursiva). Es como si estos objetos se hubieran definido de la siguiente manera.

var Object= new Function ([native code for object Object]) var String= new Function ([native code for object String]) var Number= new Function ([native code for object Number]) var Boolean= new Function ([native code for object Boolean]) var Array= new Function ([native code for object Array]) var RegExp= new Function ([native code for object RegExp]) var Function= new Function ([native code for object Function]) var UserDefinedFunction= new Function ("user defined code")

Como se mencionó anteriormente, los objetos de tipo Función pueden crear nuevos objetos usando el nuevo operador . Por ejemplo, un objeto de tipo Object , String , Number , Boolean , Array , RegExp o UserDefinedFunction se puede crear usando

var a=new Object() or var a=Object() or var a={} //Create object of type Object var a=new String() //Create object of type String var a=new Number() //Create object of type Number var a=new Boolean() //Create object of type Boolean var a=new Array() or var a=Array() or var a=[] //Create object of type Array var a=new RegExp() or var a=RegExp() //Create object of type RegExp var a=new UserDefinedFunction()

Los objetos así creados son todos objetos de tipo no funcional y devuelven su typeof === ''object'' . En todos estos casos, el objeto "a" no puede crear objetos utilizando el operador new. Entonces lo siguiente es incorrecto

var b=new a() //error. a is not typeof===''function''

El objeto incorporado en Math es typeof === ''object'' . Por lo tanto, un nuevo objeto de tipo Math no puede ser creado por un nuevo operador.

var b=new Math() //error. Math is not typeof===''function''

También tenga en cuenta que las funciones Object , Array y RegExp pueden crear un nuevo objeto sin siquiera utilizar el operador new . Sin embargo, los que siguen no lo hacen.

var a=String() // Create a new Non Object string. returns a typeof===''string'' var a=Number() // Create a new Non Object Number. returns a typeof===''number'' var a=Boolean() //Create a new Non Object Boolean. returns a typeof===''boolean''

Las funciones definidas por el usuario son casos especiales.

var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.

Dado que los objetos de tipo Función pueden crear nuevos objetos, también se denominan Constructores .

Cada Constructor / Función (ya sea integrado o definido por el usuario) cuando se define automáticamente tiene una propiedad llamada "prototipo" cuyo valor por defecto se establece como un objeto. Este objeto en sí tiene una propiedad llamada "constructor" que, de forma predeterminada, hace referencia al constructor / función .

Por ejemplo cuando definimos una función.

function UserDefinedFunction() { }

lo siguiente sucede automáticamente

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

Esta propiedad "prototipo" solo está presente en los objetos de tipo Función (y nunca en los objetos de tipo Sin función ).

Esto se debe a que cuando se crea un nuevo objeto (utilizando un nuevo operador), hereda todas las propiedades y métodos del objeto prototipo actual de la función Constructor, es decir, se crea una referencia interna en el objeto recién creado que hace referencia al objeto referenciado por el objeto prototipo actual de la función Constructor.

Esta "referencia interna" que se crea en el objeto para hacer referencia a las propiedades heredadas se conoce como prototipo del objeto (que hace referencia al objeto referenciado por la propiedad "prototipo" del Constructor, pero es diferente de él). Para cualquier objeto (Función o No Función), se puede recuperar utilizando el método Object.getPrototypeOf () . Usando este método se puede rastrear la cadena prototipo de un objeto.

Además, cada objeto que se crea ( tipo de función o tipo sin función ) tiene una propiedad de "constructor" que se hereda del objeto referenciado por la propiedad prototipo de la función de constructor. Por defecto, esta propiedad "constructor" hace referencia a la función Constructor que la creó (si no se cambia el "prototipo" predeterminado de la función Constructor ).

Para todos los objetos de tipo Función, la función constructora siempre es función Función () {}

Para los objetos de tipo Sin función (por ejemplo, Javascript Built in Math object), la función constructora es la función que lo creó. Para el objeto Math es la función Object () {} .

Todo el concepto explicado anteriormente puede ser un poco difícil de entender sin ningún código de apoyo. Lea el siguiente código línea por línea para entender el concepto. Intenta ejecutarlo para tener un mejor entendimiento.

function UserDefinedFunction() { } /* creating the above function automatically does the following as mentioned earlier UserDefinedFunction.prototype={constructor:UserDefinedFunction} */ var newObj_1=new UserDefinedFunction() alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype) //Displays true alert(newObj_1.constructor) //Displays function UserDefinedFunction //Create a new property in UserDefinedFunction.prototype object UserDefinedFunction.prototype.TestProperty="test" alert(newObj_1.TestProperty) //Displays "test" alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays "test" //Create a new Object var objA = { property1 : "Property1", constructor:Array } //assign a new object to UserDefinedFunction.prototype UserDefinedFunction.prototype=objA alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype) //Displays false. The object referenced by UserDefinedFunction.prototype has changed //The internal reference does not change alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction alert(newObj_1.TestProperty) //This shall still Display "test" alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display "test" //Create another object of type UserDefinedFunction var newObj_2= new UserDefinedFunction(); alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true. alert(newObj_2.constructor) //Displays function Array() alert(newObj_2.property1) //Displays "Property1" alert(Object.getPrototypeOf(newObj_2).property1) //Displays "Property1" //Create a new property in objA objA.property2="property2" alert(objA.property2) //Displays "Property2" alert(UserDefinedFunction.prototype.property2) //Displays "Property2" alert(newObj_2.property2) // Displays Property2 alert(Object.getPrototypeOf(newObj_2).property2) //Displays "Property2"

La cadena de prototipos de cada objeto en última instancia se remonta al Object.prototype (que a su vez no tiene ningún objeto prototipo). El siguiente código se puede usar para rastrear la cadena de prototipo de un objeto

var o=Starting object; do { alert(o + "/n" + Object.getOwnPropertyNames(o)) }while(o=Object.getPrototypeOf(o))

La cadena de prototipos para varios objetos funciona de la siguiente manera.

  • Cada objeto Function (incluido el objeto Function incorporado) -> Function.prototype -> Object.prototype -> null
  • Objetos simples (creados por el nuevo objeto () o {} incluido el objeto matemático incorporado) -> Object.prototype -> null
  • Objeto creado con new o Object.create -> Una o más cadenas prototipo -> Object.prototype -> null

Para crear un objeto sin ningún prototipo usa lo siguiente:

var o=Object.create(null) alert(Object.getPrototypeOf(o)) //Displays null

Uno podría pensar que establecer la propiedad prototipo del Constructor en nulo creará un objeto con un prototipo nulo. Sin embargo, en tales casos, el prototipo del objeto recién creado se establece en Object.prototype y su constructor se establece en la función Object. Esto se demuestra por el siguiente código

function UserDefinedFunction(){} UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.) var o=new UserDefinedFunction() alert(Object.getPrototypeOf(o)==Object.prototype) //Displays true alert(o.constructor) //Displays Function Object

Siguiendo en el resumen de este artículo.

  • Hay dos tipos de objetos Tipos de funciones y Tipos sin funciones
  • Solo los objetos de tipo Función pueden crear un nuevo objeto utilizando el operador new . Los objetos así creados son objetos de tipo no funcional . Los objetos de tipo Sin función no pueden seguir creando un objeto utilizando el operador new .

  • Todos los objetos de tipo Función de forma predeterminada tienen una propiedad "prototipo" . Esta propiedad "prototipo" hace referencia a un objeto que tiene una propiedad "constructor" que, de forma predeterminada, hace referencia al propio tipo de función .

  • Todos los objetos ( Tipo de función y Tipo sin función ) tienen una propiedad de "constructor" que, de forma predeterminada, hace referencia al objeto de tipo Función / Constructor que lo creó.

  • Cada objeto que se crea internamente hace referencia al objeto referenciado por la propiedad "prototipo" del Constructor que lo creó. Este objeto se conoce como el prototipo del objeto creado (que es diferente de la propiedad "prototipo" de los objetos de tipo Función que hace referencia). De esta manera, el objeto creado puede acceder directamente a los métodos y propiedades definidos en el objeto referenciado por la propiedad "prototipo" del Constructor (en el momento de la creación del objeto).

  • El prototipo de un objeto (y, por lo tanto, sus nombres de propiedad heredados) se puede recuperar utilizando el método Object.getPrototypeOf () . De hecho, este método se puede utilizar para navegar por toda la cadena de prototipos del objeto.

  • La cadena de prototipos de cada objeto se remonta finalmente a Object.prototype (a menos que el objeto se cree utilizando Object.create (nulo), en cuyo caso el objeto no tiene prototipo).

  • typeof (new Array ()) === ''objeto'' es un diseño de lenguaje y no un error como señala Douglas Crockford

  • Establecer la propiedad prototipo del Constructor en nulo (o undefined, number, true, false, string) no creará un objeto con un prototipo nulo. En tales casos, el prototipo del objeto recién creado se establece en Object.prototype y su constructor se establece en la función Object.

Espero que esto ayude.


Javascript no tiene herencia en el sentido habitual, pero tiene la cadena de prototipo.

cadena prototipo

Si un miembro de un objeto no se encuentra en el objeto, lo busca en la cadena de prototipo. La cadena se compone de otros objetos. Se puede acceder al prototipo de una instancia dada con la variable __proto__ . Cada objeto tiene uno, ya que no hay diferencia entre clases e instancias en javascript.

La ventaja de agregar una función / variable al prototipo es que debe estar en la memoria solo una vez, no para cada instancia.

También es útil para la herencia, porque la cadena del prototipo puede constar de muchos otros objetos.



prototype te permite hacer clases. Si no usas prototype entonces se convierte en una estática.

Aquí hay un breve ejemplo.

var obj = new Object(); obj.test = function() { alert(''Hello?''); };

En el caso anterior, tiene una prueba de llamada a la función estática. Solo se puede acceder a esta función mediante obj.test, donde se puede imaginar que obj sea una clase.

donde como en el código de abajo

function obj() { } obj.prototype.test = function() { alert(''Hello?''); }; var obj2 = new obj(); obj2.test();

El obj se ha convertido en una clase que ahora puede ser instanciada. Pueden existir múltiples instancias de obj y todas tienen la función de test .

Lo anterior es mi entendimiento. Lo estoy convirtiendo en una wiki comunitaria, para que la gente pueda corregirme si me equivoco.


Desempeño un papel como profesor de JavaScript y el concepto de prototipo siempre ha sido un tema controvertido para cubrir cuando enseño. Me tomó un tiempo encontrar un buen método para aclarar el concepto, y ahora, en este texto, intentaré explicar cómo funciona el prototipo de JavaScript.

Este es un modelo de objeto basado en un prototipo muy simple que se consideraría una muestra durante la explicación, sin ningún comentario todavía:

function Person(name){ this.name = name; } Person.prototype.getName = function(){ console.log(this.name); } var person = new Person("George");

Hay algunos puntos cruciales que debemos tener en cuenta antes de pasar por el concepto de prototipo.

1- Cómo funcionan realmente las funciones de JavaScript:

Para dar el primer paso, tenemos que descubrir cómo funcionan realmente las funciones de JavaScript, como una función similar a una clase que usa this palabra clave en ella o simplemente como una función regular con sus argumentos, qué hace y qué devuelve.

Digamos que queremos crear un modelo de objeto Person . pero en este paso, intentaré hacer exactamente lo mismo sin usar el prototype y la new palabra clave .

Así que en este paso las functions , los objects y this palabra clave, son todo lo que tenemos.

La primera pregunta sería cómo this palabra clave podría ser útil sin utilizar una new palabra clave .

Entonces, para responder a eso, digamos que tenemos un objeto vacío, y dos funciones como:

var person = {}; function Person(name){ this.name = name; } function getName(){ console.log(this.name); }

y ahora, sin usar una new palabra clave, cómo podríamos usar estas funciones. Así que JavaScript tiene 3 formas diferentes de hacerlo:

a. La primera forma es llamar a la función como una función regular:

Person("George"); getName();//would print the "George" in the console

en este caso, este sería el objeto de contexto actual, que generalmente es el objeto de window global en el navegador o GLOBAL en Node.js Significa que tendríamos, window.name en el navegador o GLOBAL.name en Node.js, con "George" como su valor.

segundo. Podemos adjuntarlos a un objeto, como sus propiedades.

- La forma más sencilla de hacerlo es modificar el objeto de person vacío, como:

person.Person = Person; person.getName = getName;

De esta manera podemos llamarlos como:

person.Person("George"); person.getName();// -->"George"

y ahora el objeto person es como:

Object {Person: function, getName: function, name: "George"}

- La otra forma de adjuntar una propiedad a un objeto es usar el prototype de ese objeto que se puede encontrar en cualquier objeto de JavaScript con el nombre de __proto__ , y he tratado de explicarlo un poco en la parte del resumen. Así podríamos obtener el resultado similar haciendo:

person.__proto__.Person = Person; person.__proto__.getName = getName;

Pero de esta manera, lo que realmente estamos haciendo es modificar el Object.prototype , porque cada vez que creamos un objeto JavaScript utilizando literales ( { ... } ), se crea basado en el Object.prototype , lo que significa que se adjunta a la recién creada objeto como un atributo llamado __proto__ , así que si lo cambiamos, como hemos hecho en nuestro fragmento de código anterior, todos los objetos de JavaScript se cambiarán, no es una buena práctica. Entonces, ¿cuál podría ser la mejor práctica ahora:

person.__proto__ = { Person: Person, getName: getName };

y ahora otros objetos están en paz, pero todavía no parece ser una buena práctica. Así que todavía tenemos una solución más, pero para usar esta solución deberíamos volver a esa línea de código donde se creó el objeto person ( var person = {}; ) y luego cambiarlo como:

var propertiesObject = { Person: Person, getName: getName }; var person = Object.create(propertiesObject);

lo que hace es crear un nuevo Object JavaScript y adjuntar el objeto de propertiesObject al objeto __proto__ . Así que para asegurarse de que puede hacer:

console.log(person.__proto__===propertiesObject); //true

Pero el punto difícil aquí es que tiene acceso a todas las propiedades definidas en __proto__ en el primer nivel del objeto person (lea la parte del resumen para más detalles).

Como ve usando cualquiera de estos dos modos, this apuntaría exactamente al objeto person .

do. JavaScript tiene otra forma de proporcionar a la función this , que es usar call o apply para invocar la función.

El método apply () llama a una función con un determinado valor y argumentos proporcionados como una matriz (o un objeto similar a una matriz).

y

El método call () llama a una función con un determinado valor y argumentos proporcionados individualmente.

De esta manera, que es mi favorito, podemos llamar fácilmente nuestras funciones como:

Person.call(person, "George");

o

//apply is more useful when params count is not fixed Person.apply(person, ["George"]); getName.call(person); getName.apply(person);

estos 3 métodos son los pasos iniciales importantes para descubrir la funcionalidad del prototipo.

2- ¿Cómo funciona la new palabra clave?

este es el segundo paso para entender la funcionalidad de .prototype . esto es lo que uso para simular el proceso:

function Person(name){ this.name = name; } my_person_prototype = { getName: function(){ console.log(this.name); } };

En esta parte, intentaré seguir todos los pasos que toma JavaScript, sin usar la new palabra clave y el prototype , cuando usas una new . así que cuando hacemos new Person("George") , la función de Person sirve como un constructor, esto es lo que hace JavaScript, uno por uno:

a. En primer lugar, crea un objeto vacío, básicamente un hash vacío como:

var newObject = {};

segundo. El siguiente paso que toma JavaScript es adjuntar todos los objetos prototipo al objeto recién creado.

tenemos my_person_prototype aquí similar al objeto prototipo.

for(var key in my_person_prototype){ newObject[key] = my_person_prototype[key]; }

No es la forma en que JavaScript en realidad adjunta las propiedades que se definen en el prototipo. La forma real está relacionada con el concepto de cadena prototipo.

a. & b. En lugar de estos dos pasos, puede obtener exactamente el mismo resultado haciendo:

var newObject = Object.create(my_person_prototype); //here you can check out the __proto__ attribute console.log(newObject.__proto__ === my_person_prototype); //true //and also check if you have access to your desired properties console.log(typeof newObject.getName);//"function"

Ahora podemos llamar a la función getName en nuestro my_person_prototype :

newObject.getName();

do. entonces le da ese objeto al constructor,

Podemos hacer esto con nuestra muestra como:

Person.call(newObject, "George");

o

Person.apply(newObject, ["George"]);

entonces el constructor puede hacer lo que quiera, porque este dentro de ese constructor es el objeto que se acaba de crear.

Ahora el resultado final antes de simular los otros pasos: Objeto {nombre: "George"}

Resumen:

Básicamente, cuando usa la nueva palabra clave en una función, está llamando a esa función y esa función sirve como un constructor, por lo que cuando dice:

new FunctionName()

JavaScript internamente crea un objeto, un hash vacío y luego le da ese objeto al constructor, luego el constructor puede hacer lo que quiera, porque este dentro del constructor es el objeto que se acaba de crear y luego le da ese objeto, por supuesto. si no ha usado la declaración de retorno en su función o si ha puesto un return undefined; Al final de tu función corporal.

Entonces, cuando JavaScript va a buscar una propiedad en un objeto, lo primero que hace es buscarlo en ese objeto. Y luego hay una propiedad secreta [[prototype]] que usualmente la tenemos como __proto__ y esa propiedad es lo que JavaScript ve a continuación. Y cuando mira a través de __proto__ , en la medida en que es otro objeto de JavaScript, tiene su propio atributo __proto__ , sube y sube hasta que llega al punto donde el próximo __proto__ es nulo. El punto es el único objeto en JavaScript que su atributo __proto__ es nulo es el objeto Object.prototype :

console.log(Object.prototype.__proto__===null);//true

Y así es como funciona la herencia en JavaScript.

En otras palabras, cuando tiene una propiedad prototipo en una función y llama a una nueva en eso, después de que JavaScript termine de mirar las propiedades recién creadas en el objeto, irá a mirar el .prototype la función y también es posible que este objeto Tiene su propio prototipo interno. y así.


Es solo que ya tienes un objeto con Object.new pero aún no tienes un objeto cuando usas la sintaxis del constructor.


Hay dos entidades distintas pero relacionadas aquí que necesitan una explicación:

  • La .prototypepropiedad de las funciones.
  • La propiedad [[Prototype]] [1] de todos los objetos [2] .

Estas son dos cosas diferentes.

La [[Prototype]]propiedad:

Esta es una propiedad que existe en todos los [2] objetos.

Lo que se almacena aquí es otro objeto que, como un objeto en sí, tiene un objeto [[Prototype]]propio que apunta a otro objeto. Ese otro objeto tiene una [[Prototype]]propia. Esta historia continúa hasta que alcanza el objeto prototípico que proporciona métodos a los que se puede acceder en todos los objetos (me gusta .toString).

La [[Prototype]]propiedad forma parte de lo que forma la [[Prototype]]cadena. Esta cadena de [[Prototype]]objetos es lo que se examina cuando, por ejemplo, [[Get]]o [[Set]]se realizan operaciones en un objeto:

var obj = {} obj.a // [[Get]] consults prototype chain obj.b = 20 // [[Set]] consults prototype chain

La .prototypepropiedad:

Esta es una propiedad que solo se encuentra en las funciones. Usando una función muy simple:

function Bar(){};

La .prototypepropiedad contiene un objeto que se asignará b.[[Prototype]]cuando lo hagas var b = new Bar. Usted puede examinar esto fácilmente:

// Both assign Bar.prototype to b1/b2[[Prototype]] var b = new Bar; // Object.getPrototypeOf grabs the objects [[Prototype]] console.log(Object.getPrototypeOf(b) === Bar.prototype) // true

Uno de los más importantes .prototypees el Object.prototype . Este prototipo contiene el objeto prototípico que [[Prototype]]contienen todas las cadenas. En él, se definen todos los métodos disponibles para nuevos objetos:

// Get properties that are defined on this object console.log(Object.getOwnPropertyDescriptors(Object.prototype))

Ahora, como .prototypees un objeto, tiene una [[Prototype]]propiedad. Cuando no hace ninguna asignación a Function.prototype, el .prototype''s [[Prototype]]apunta al objeto prototípico ( Object.prototype). Esto se realiza automáticamente cada vez que crea una nueva función.

De esta manera, cada vez que realice new Bar;la cadena de prototipos se configura para usted, obtendrá todo lo definido Bar.prototypey todo lo definido en Object.prototype:

var b = new Bar; // Get all Bar.prototype properties console.log(b.__proto__ === Bar.prototype) // Get all Object.prototype properties console.log(b.__proto__.__proto__ === Object.prototype)

Cuando haces hacer asignaciones a Function.prototypetodo lo que está haciendo es extender la cadena de prototipo para incluir otro objeto. Es como una inserción en una lista enlazada individualmente.

Básicamente, esto altera la [[Prototype]]cadena permitiendo que las propiedades que están definidas en el objeto asignado Function.prototypesean vistas por cualquier objeto creado por la función.

[1: Eso no confundirá a nadie; puesto a disposición a través de la __proto__propiedad en muchas implementaciones.
[2]: Todos excepto null.


Puede ayudar a categorizar las cadenas de prototipos en dos categorías.

Considere el constructor:

function Person() {}

El valor de Object.getPrototypeOf(Person)es una función. De hecho, lo es Function.prototype. Dado que Personse creó como una función, comparte el mismo objeto de función prototipo que tienen todas las funciones. Es lo mismo que Person.__proto__, pero esa propiedad no debe ser utilizada. De todos modos, con Object.getPrototypeOf(Person)usted efectivamente subir la escalera de lo que se llama la cadena de prototipo.

La cadena en dirección hacia arriba se ve así:

PersonFunction.prototypeObject.prototype(punto final)

Es importante que esta cadena de prototipos tenga poco que ver con los objetos que se Personpueden construir . Esos objetos construidos tienen su propio prototipo de cadena, y esta cadena no puede tener un antepasado común en común con el mencionado anteriormente.

Tomemos por ejemplo este objeto:

var p = new Person();

p no tiene una relación directa de prototipo-cadena con la persona . Su relación es diferente. El objeto p tiene su propia cadena prototipo. Usando Object.getPrototypeOf, encontrarás que la cadena es la siguiente:

pPerson.prototypeObject.prototype(punto final)

No hay ningún objeto de función en esta cadena (aunque eso podría ser).

Así Personparece estar relacionado con dos tipos de cadenas, que viven sus propias vidas. Para "saltar" de una cadena a la otra, usas:

  1. .prototype: saltar de la cadena del constructor a la cadena del objeto creado. Por lo tanto, esta propiedad solo se define para objetos de función (ya newque solo se puede utilizar en funciones).

  2. .constructor : saltar de la cadena del objeto creado a la cadena del constructor.

Aquí hay una presentación visual de las dos cadenas de prototipos involucradas, representadas como columnas:

Resumir:

La prototypepropiedad no proporciona información de la cadena de prototipo del sujeto , sino de objetos creados por el sujeto.

No es de extrañar que el nombre de la propiedad prototypepueda llevar a confusión. Tal vez hubiera sido más claro si esta propiedad hubiera sido nombrada prototypeOfConstructedInstanceso algo en esa línea.

Puedes saltar de un lado a otro entre las dos cadenas de prototipos:

Person.prototype.constructor === Person

Esta simetría se puede romper asignando explícitamente un objeto diferente a la prototypepropiedad (más sobre esto más adelante).

Crear una función, obtener dos objetos

Person.prototypees un objeto que se creó al mismo tiempo que se creó la función Person. Tiene Personcomo constructor, aunque ese constructor no se haya ejecutado todavía. Entonces se crean dos objetos al mismo tiempo:

  1. La Personpropia funcion
  2. El objeto que actuará como prototipo cuando la función se llame como un constructor.

Ambos son objetos, pero tienen roles diferentes: el objeto de función construye , mientras que el otro objeto representa el prototipo de cualquier objeto que la función construirá. El objeto prototipo se convertirá en el padre del objeto construido en su cadena de prototipo.

Dado que una función es también un objeto, también tiene su propio padre en su propia cadena de prototipo, pero recuerde que estas dos cadenas tienen que ver con cosas diferentes.

Aquí hay algunas ecualidades que podrían ayudar a comprender el problema: todas estas impresiones true:

function Person() {}; // This is prototype chain info for the constructor (the function object): console.log(Object.getPrototypeOf(Person) === Function.prototype); // Step further up in the same hierarchy: console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype); console.log(Object.getPrototypeOf(Object.prototype) === null); console.log(Person.__proto__ === Function.prototype); // Here we swap lanes, and look at the constructor of the constructor console.log(Person.constructor === Function); console.log(Person instanceof Function); // Person.prototype was created by Person (at the time of its creation) // Here we swap lanes back and forth: console.log(Person.prototype.constructor === Person); // Although it is not an instance of it: console.log(!(Person.prototype instanceof Person)); // Instances are objects created by the constructor: var p = new Person(); // Similarly to what was shown for the constructor, here we have // the same for the object created by the constructor: console.log(Object.getPrototypeOf(p) === Person.prototype); console.log(p.__proto__ === Person.prototype); // Here we swap lanes, and look at the constructor console.log(p.constructor === Person); console.log(p instanceof Person);

Añadiendo niveles a la cadena de prototipos.

Aunque se crea un objeto prototipo cuando crea una función de constructor, puede ignorar ese objeto y asignar otro objeto que debe usarse como prototipo para cualquier instancia posterior creada por ese constructor.

Por ejemplo:

function Thief() { } var p = new Person(); Thief.prototype = p; // this determines the prototype for any new Thief objects: var t = new Thief();

Ahora la cadena prototipo de t es un paso más larga que la de p :

tpPerson.prototypeObject.prototype(punto final)

La otra cadena de prototipos ya no es más: Thiefy Personson hermanos que comparten el mismo padre en su cadena de prototipos:

Person}
Thief} → Function.prototypeObject.prototype(punto final)

El gráfico presentado anteriormente se puede extender a esto (el original Thief.prototypese omite):

Las líneas azules representan cadenas prototipo, las otras líneas coloreadas representan otras relaciones:

  • entre un objeto y su constructor
  • entre un constructor y el objeto prototipo que se usará para construir objetos

Considere el siguiente keyValueStoreobjeto:

var keyValueStore = (function() { var count = 0; var kvs = function() { count++; this.data = {}; this.get = function(key) { return this.data[key]; }; this.set = function(key, value) { this.data[key] = value; }; this.delete = function(key) { delete this.data[key]; }; this.getLength = function() { var l = 0; for (p in this.data) l++; return l; } }; return { // Singleton public properties ''create'' : function() { return new kvs(); }, ''count'' : function() { return count; } }; })();

Puedo crear una nueva instancia de este objeto haciendo esto:

kvs = keyValueStore.create();

Cada instancia de este objeto tendría las siguientes propiedades públicas:

  • data
  • get
  • set
  • delete
  • getLength

Ahora, supongamos que creamos 100 instancias de este keyValueStoreobjeto. A pesar de que get, set, delete, getLengthva a hacer exactamente lo mismo para cada uno de estos 100 casos, cada caso tiene su propia copia de esta función.

Ahora, imagínese si usted podría tener una sola get, set, deletey getLengthcopia, y cada instancia haría referencia a esa misma función. Esto sería mejor para el rendimiento y requeriría menos memoria.

Ahí es donde entran los prototipos. Un prototipo es un "plano" de propiedades que se hereda pero no se copia por las instancias. Entonces, esto significa que existe solo una vez en la memoria para todas las instancias de un objeto y es compartido por todas esas instancias.

Ahora, considera el keyValueStoreobjeto de nuevo. Podría reescribirlo así:

var keyValueStore = (function() { var count = 0; var kvs = function() { count++; this.data = {}; }; kvs.prototype = { ''get'' : function(key) { return this.data[key]; }, ''set'' : function(key, value) { this.data[key] = value; }, ''delete'' : function(key) { delete this.data[key]; }, ''getLength'' : function() { var l = 0; for (p in this.data) l++; return l; } }; return { ''create'' : function() { return new kvs(); }, ''count'' : function() { return count; } }; })();

Esto hace EXACTAMENTE lo mismo que la versión anterior del keyValueStoreobjeto, excepto que todos sus métodos ahora se colocan en un prototipo. Lo que esto significa es que las 100 instancias ahora comparten estos cuatro métodos en lugar de que cada uno tenga su propia copia.


Cuando un constructor crea un objeto, ese objeto hace referencia implícitamente a la propiedad "prototipo" del constructor con el propósito de resolver las referencias de propiedad. Se puede hacer referencia a la propiedad "prototipo" del constructor mediante la expresión de programa constructor.prototype, y las propiedades agregadas al prototipo de un objeto se comparten, mediante herencia, por todos los objetos que comparten el prototipo.


Déjame que te cuente mi comprensión de los prototipos. No voy a comparar la herencia aquí con otros idiomas. Desearía que la gente dejara de comparar idiomas y que entendiera el lenguaje como tal. Comprender los prototipos y la herencia prototípica es tan simple, como les mostraré a continuación.

Prototipo es como un modelo, basado en el que creas un producto. El punto crucial a comprender es que cuando creas un objeto utilizando otro objeto como prototipo, el vínculo entre el prototipo y el producto es siempre duradero. Por ejemplo:

var model = {x:2}; var product = Object.create(model); model.y = 5; product.y =>5

Cada objeto contiene una propiedad interna llamada [[prototipo]], a la que puede acceder la Object.getPrototypeOf()función. Object.create(model)crea un nuevo objeto y establece su propiedad [[prototype]] en el modelo de objeto . Por lo tanto, cuando lo hagas Object.getPrototypeOf(product), obtendrás el modelo de objeto .

Las propiedades en el producto se manejan de la siguiente manera:

  • Cuando se accede a una propiedad para solo leer su valor, se busca en la cadena de alcance. La búsqueda de la variable comienza desde el producto hasta su prototipo. Si se encuentra una variable de este tipo en la búsqueda, la búsqueda se detiene allí mismo y se devuelve el valor. Si tal variable no se puede encontrar en la cadena de alcance, se devuelve indefinido.
  • Cuando se escribe (modifica) una propiedad, la propiedad siempre se escribe en el objeto del producto . Si el producto aún no tiene dicha propiedad, se crea y escribe de manera implícita.

Tal vinculación de objetos que utilizan la propiedad prototipo se denomina herencia prototípica. Ahí es tan simple, ¿de acuerdo?


El concepto de prototypalherencia es uno de los más complicados para muchos desarrolladores. Intentemos entender la raíz del problema para entender prototypal inheritancemejor. Vamos a empezar con una plainfunción.

Si utilizamos un newoperador en el Tree function, lo llamamos como una constructorfunción.

Cada JavaScriptfunción tiene una prototype. Cuando inicias sesión Tree.prototype, obtienes ...

Si observa la console.log()salida anterior , podría ver una propiedad de constructor Tree.prototypey una __proto__propiedad también. El __proto__representa la prototypeque este functionse basa fuera, y ya que esto es sólo una llanura JavaScript functionsin inheritancecreado todavía, se refiere a la Object prototypeque es algo construido justo en el tener JavaScript ...

Object.prototype

Esto tiene cosas como .toString, .toValue, .hasOwnPropertyetc ...

__proto__el cual fue traído mi mozilla está en desuso y es reemplazado por un Object.getPrototypeOfmétodo para obtener el object''s prototype.

Object.getPrototypeOf(Tree.prototype); // Object {}

Añadamos un método a nuestro Tree prototype.

Hemos modificado el Rooty le hemos añadido una functionrama.

Eso significa que cuando creas uno instancede Tree, puedes llamar a su branchmétodo.

También podemos añadir primitiveso objectsa nuestro Prototype.

Vamos a añadir una child-treea nuestra Tree.

Aquí lo Childheredamos prototypede Tree, lo que estamos haciendo aquí es usar un Object.create()método para crear un nuevo objeto basado en lo que se pasa, aquí está Tree.prototype. En este caso, lo que estamos haciendo es configurar el prototipo de Niño en un nuevo objeto que se ve idéntico al Treeprototipo. A continuación estamos configurando el Child''s constructor to Child, si no lo apuntamos Tree().

ChildAhora tiene su propio prototype, sus __proto__puntos Treey Tree''s prototypepuntos a la base Object.

Child | / / Tree.prototype - branch | | / / Object.prototype -toString -valueOf -etc., etc.

Ahora creas un instanceof Childy call branchque está disponible originalmente en Tree. En realidad no hemos definido nuestro branchen el Child prototype. PERO, en el Root prototypecual el niño hereda.

En JS todo no es un objeto, todo puede actuar como un objeto.

JavascriptTiene primitivas como strings, number, booleans, undefined, null.no lo son object(ie reference types), pero ciertamente pueden actuar como un object. Veamos un ejemplo aquí.

En la primera línea de este listado, un primitivevalor de cadena se asigna a nombre. La segunda línea trata el nombre como una objecty llama charAt(0)usando notación de puntos.

Esto es lo que sucede detrás de escena: // lo que hace el JavaScriptmotor

El String objectexiste solo para una declaración antes de ser destruido (proceso llamado autoboxing). Volvamos de nuevo a nuestro prototypal inheritance.

  • JavascriptSoporta la herencia a través delegationde prototypes.
  • Cada uno Functiontiene una prototypepropiedad, que se refiere a otro objeto.
  • properties/functionsSe miran desde objectsí mismo o vía prototypecadena si no existe.

A prototypeen JS es un objeto que yieldsusted al padre de otro object. [es decir, delegación] Delegation significa que si no puede hacer algo, le dirá a otra persona que lo haga por usted.

https://jsfiddle.net/say0tzpL/1/

Si busca el violín anterior, dog tiene acceso al toStringmétodo, pero no está disponible en él, pero está disponible a través de la cadena de prototipos a la que delegan.Object.prototype

Si observa el siguiente, estamos tratando de acceder al callmétodo que está disponible en todos function.

https://jsfiddle.net/rknffckc/

Si busca el violín anterior, la Profilefunción tiene acceso al callmétodo, pero no está disponible en él, pero está disponible a través de la cadena de prototipos a la que delegan.Function.prototype

Nota: prototype es una propiedad del constructor de funciones, mientras que __proto__es una propiedad de los objetos construidos a partir del constructor de funciones. Cada función viene con una prototypepropiedad cuyo valor es un vacío object. Cuando creamos una instancia de la función, obtenemos una propiedad interna [[Prototype]]o __proto__cuya referencia es el prototipo de la función constructor.

El diagrama anterior parece un poco complicado, pero muestra la imagen completa de cómo prototype chainingfunciona. Vamos a caminar a través de esto lentamente:

Hay dos instancias b1y b2, cuyo constructor es Bary el principal es Foo y tiene dos métodos de la cadena de prototipo identifyy speakvia BaryFoo

https://jsfiddle.net/kbp7jr7n/

Si busca el código anterior, tenemos un Fooconstructor que tiene el método identify()y el Barconstructor que tiene un speakmétodo. Creamos dos Barinstancias b1y b2cuyo tipo de padre es Foo. Ahora, mientras llamamos al speakmétodo de Bar, podemos identificar quién llama el hablar a través de la prototypecadena.

BarAhora tiene todos los métodos de los Foocuales se definen en su prototype. Vamos a profundizar más en la comprensión de la Object.prototypey Function.prototype, y cómo se relacionan. Si buscas el constructor de Foo, Bary Objectson Function constructor.

El prototypede Bares Foo, prototypede Fooes Objecty si miras de cerca el prototypede Fooestá relacionado con Object.prototype.

Antes de cerrar esto, simplemente envolvamos con un pequeño fragmento de código aquí para resumir todo lo anterior . Estamos utilizando el instanceofoperador aquí para verificar si un objecttiene en su prototypecadena la prototypepropiedad de una constructorque a continuación resume todo el diagrama grande.

Espero que este complemento sea algo de información, sé que este tipo de cosas podría ser grande para comprender ... en palabras simples , ¡¡¡solo son objetos vinculados a objetos !!!!


Me pareció útil explicar la "cadena de prototipos" como una convención recursiva cuando obj_n.prop_Xse hace referencia a:

Si obj_n.prop_Xno existe, verifique obj_n+1.prop_Xdóndeobj_n+1 = obj_n.[[prototype]]

Si prop_Xfinalmente se encuentra en el objeto prototipo k-th entonces

obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X

Puedes encontrar un gráfico de la relación de los objetos Javascript por sus propiedades aquí:

http://jsobjects.org



Siempre me gustan las analogías cuando se trata de entender este tipo de cosas. La "herencia prototípica" es bastante confusa en comparación con la herencia de bajos de clase en mi opinión, aunque los prototipos son un paradigma mucho más simple. De hecho, con los prototipos, realmente no hay herencia, por lo que el nombre en sí mismo es engañoso, es más un tipo de "delegación".

Imagina esto ....

Estás en la escuela secundaria, estás en clase y tienes un cuestionario que se debe entregar hoy, pero no tienes un bolígrafo para completar tus respuestas. Doh!

Estás sentado junto a tu amigo Finnius, que podría tener una pluma. Lo preguntas, y él mira a su escritorio sin éxito, pero en lugar de decir "No tengo un bolígrafo", es un buen amigo que consulta con su otro amigo Derp si tiene un bolígrafo. Derp sí tiene un bolígrafo de repuesto y se lo pasa a Finnius, quien se lo pasa a usted para que complete su cuestionario. Derp ha confiado la pluma a Finnius, quien le ha delegado la pluma para su uso.

Lo importante aquí es que Derp no te da la pluma, ya que no tienes una relación directa con él.

Este es un ejemplo simplificado de cómo funcionan los prototipos, donde se busca un árbol de datos para lo que está buscando.


otro esquema que muestra __proto__ , prototipo y relaciones constructoras :