Para comprender el prototipo en JS, primero debe comprender los siguientes conceptos
1. Todo en JS es un objeto
2. Todo en JS se deriva del objeto, es decir, el punto final de la cadena prototipo de todas las cosas apunta a Object.Prototype
// ["Constructor", "ToString", "TOLOCALECRING", "VALOROF", "ASOWNPROPERTY", "ISPROTOTYPOF", // "PropertyIsenumerable", "__definegetter__", "__lookupGetter__", "__definesetter__", // "__lookupsetter__"] console.log (object.getOwnPropertynames (objeto.prototype));
3. La relación sutil entre constructores e instancias (objetos) en JS
Los constructores definen prototipos para acordar las especificaciones de sus instancias y luego construir instancias a través de nuevas. Su función es producir objetos.
El constructor (método) en sí es una instancia del método (función), por lo que también se puede encontrar para su __proto __ (protochain)
Object / function f () {} Este es el constructor, uno es proporcionado por la API nativa JS y la otra está personalizada
nuevo objeto () / nuevo f () es una instancia
Los ejemplos solo se pueden ver "solo" para descubrir en qué prototipo se hace en base.
El prototipo que "no puede" redefine la instancia y luego se engaña para crear una instancia de la instancia.
Práctica para producir conocimientos verdaderos, y solo observando/pensando a sí mismo, ¿puede realmente entender:
// Veamos primero lo que es el constructor // function vacía () {} función vacía () {} console.log (function.prototype, function .__ proto__); // objeto {} function vacía () {} console.log (objeto.prototype, objeto .__ proto__); función f () {} // f {} function vacía () {} console.log (f.prototype, f .__ proto__);Puede que estés mareado, desglosemos.
prototipo
El formato de la salida del prototipo es: prototipo de nombre del constructor
Primero, echemos un vistazo a qué objeto. PROTOTIPO SALIDAS.
Objeto {} -> El objeto anterior es el nombre del constructor, y el siguiente representa el prototipo. Aquí hay un {}, es decir, una instancia de un objeto de objeto (objeto vacío)
Entonces F {} entendemos lo que significa. F es el nombre del constructor, y el prototipo también es un objeto vacío
// Echemos un vistazo al ejemplo construido por el constructor var o = nuevo objeto (); // var o = {}; // objeto indefinido {} console.log (o.prototype, o .__ proto__); función f () {} var i = new f (); // indefinido f {} console.log (i.prototype, i .__ proto__);Vamos un poco más profundos y definamos el prototipo de F para ver qué pasará.
function f () {} f.prototype.a = function () {}; var i = new f (); // Undefinado F {a: function} console.log (i.prototype, i .__ proto__);De esta manera, podemos ver claramente que yo está construido a partir de F, el prototipo es {a: función}, lo que significa que se ha agregado un método A al prototipo de objeto vacío original.
Cambiemos la situación, ¿qué pasará si el prototipo que cubre completamente F?
función f () {} f.prototype = {a: function () {}}; var i = new f (); // objeto indefinido {a: function} console.log (i.prototype, i .__ proto__);Oye ~ ¿por qué indica aquí que estoy construido a partir del objeto? ¡No!
Debido a que sobrescribimos completamente el prototipo de F, de hecho, especificamos el prototipo como un objeto {a: función}, pero esto hará que la información del constructor original se pierda y se convierta en el constructor especificado por el objeto {a: función}.
Entonces, ¿cuál es el constructor del objeto {a: function}?
Porque el objeto {a: la función} es realmente relativo a
var o = {a: function () {}} // nuevo objetoEntonces el constructor de o es, por supuesto, un objeto
Correcemos este error
function f () {} f.prototype = {a: function () {}} // Vuelva a especificar el constructor correcto f.prototype.constructor = f; var i = new f (); // Undefinado F {a: function, constructor: function} console.log (i.prototype, i .__ proto__);Ahora puede obtener la información del prototipo correcta nuevamente ~
Cadena prototipo
Entonces, echemos un vistazo a qué es la cadena prototipo.
En pocas palabras, es lo mismo que la relación de herencia (cadena) en OOP. Busque capa por capa hasta el objeto final. Prototipo
Lo más importante es descubrir qué cosas en JS son los objetos (instancias). Esto es simple, ¡todo en JS es objetos!
¡Entonces debemos averiguar que cualquier objeto tiene un prototipo!
Entonces vamos a probarlo:
Objeto // Esta es una función, la función es un objeto de instancia de función, por lo que es el objeto .__ proto__ == function.prototype // Entonces el prototipo del objeto, true // Este es un objeto ordinario, por lo que la instancia del objeto pertenece a la función. Object.prototype .__ Proto__ == NULL // Función verdadera // Esta también es una función, sí! Función .__ proto__ == function.prototype // Función verdadera a () {} // Esta es una función personalizada, y sigue siendo una función después de todo, ¡eso es correcto! A .__ proto__ == function.prototype // cualquier función es una instancia de función, entonces es el prototipo de A? var a = nuevo a () a .__ proto__ == A.Prototype // La instancia A está construida por el constructor A, por lo que un prototipo de A está definido por el atributo prototipo de A.Prototype .__ Proto__ == Object.Prototype // Ejemplo de objetos ordinarios son objetosPrototipo y __proto__
Cada objeto contiene un __proto__ apuntando al "prototipo" del objeto.
Algo similar es que cada función contiene un prototipo. ¿Para qué es este objeto prototipo?
Veamos el siguiente código, usando el constructor para crear un objeto (lo anterior es crear un objeto en forma de forma literal).
function foo () {}; var foo = new foo (); console.log (foo .__ proto__);Imagínese, ¿a qué apuntará el __proto__ de este objeto foo?
¿Un objeto que contiene el atributo del constructor? No importa si no lo entiendes mucho. Imprima el atributo prototipo de la función foo y comparario con usted para saber.
function foo () {}; var foo = new foo (); console.log (foo .__ proto __); console.log (foo.prototype); console.log (foo .__ proto__ === foo.prototype);Resulta que el __proto__ del objeto foo que sale de nuevos puntos solo al prototipo de la función foo.
foo .__ proto__ -> foo.prototype
¿Cuál es el punto de diseñar JS como este? Recordando lo que se mencionó anteriormente, en el mundo de JS, los objetos no se crean en función de las clases (moldes), sino que se derivan de los prototipos (otro objeto).
Cuando realizamos nuevas operaciones para crear un nuevo objeto, no profundizaremos en la implementación específica de nuevas operaciones, pero estamos seguros de una cosa, es decir, señalamos un objeto prototipo para el nuevo objeto __proto__.
Solo este código
función foo () {}; var foo = new foo ();¿Quién es Foo .__ Proto__ señalando? ¿Por qué no puedes señalar a la función foo en sí? Aunque la función también es un objeto, hablaré sobre ella en detalle si tiene la oportunidad. Pero ciertamente no es apropiado señalar a Foo .__ Proto__foo, porque Foo es una función con mucho código lógico. Como objeto, no tiene sentido heredar el procesamiento lógico. Lo que quiere heredar es el atributo del "objeto prototipo".
Por lo tanto, cada función generará automáticamente un objeto prototipo, y el __proto__ del objeto nuevo desde esta función apunta al prototipo de esta función.
foo .__ proto__ -> foo.prototype
Resumir
Después de decir tanto, todavía no lo he explicado por completo, por lo que es mejor estar en la imagen anterior. He hecho referencia a fotos de otros internautas, pero siempre siento que no expliqué claramente, así que me dibujé una foto. Si creo que el mío es bueno, ¡por favor me gusta! (He hecho todo lo posible para dibujarlo).
Tomemos esta foto y recuerde los siguientes hechos:
1. Hay un atributo _proto_ en cada objeto.
No hay concepto de una clase (molde) en el mundo JS. Los objetos se derivan de otro objeto (proto), por lo que habrá un atributo _proto_ en cada objeto que apunta a su objeto prototipo. (Consulte el Obj Obj definido en forma literal en la esquina superior izquierda. Abre un espacio para almacenar las propias propiedades del objeto en la memoria y genera un _proto_ apuntando a su prototipo: el objeto prototipo de nivel superior).
2. Cada función tiene una propiedad prototipo.
¿Por qué se llama "Constructor" un constructor? Porque quiere construir un objeto. Entonces, según el primer hecho anterior, ¿a quién apunta el atributo _proto_ del nuevo objeto construido? No puedes señalar el constructor en sí. Aunque también es un objeto, no desea que el nuevo objeto herede las propiedades y métodos de la función. Por lo tanto, cada constructor tendrá un atributo prototipo, apuntando a un objeto como el prototipo del nuevo objeto construido por este constructor.
3. Las funciones también son objetos.
Cada función tiene algunas propiedades y métodos comunes, como aplicar ()/call (), etc. pero ¿cómo se heredan estos métodos comunes? ¿Cómo se crean las funciones? Imagínese, todo es un objeto, incluidas las funciones, y es un objeto construido a través de un constructor. Luego, de acuerdo con el segundo hecho anterior, cada función también tendrá un prototipo que apunta a su constructor. La función de este constructor es la función, y todas las funciones en JS se construyen a partir de la función. Las propiedades generales y los métodos de funciones se almacenan en la función prototipo de objeto.