Descripción general
Todos los objetos en JavaScript tienen su propia cadena de herencia. Es decir, cada objeto hereda otro objeto, que se llama objeto "prototipo". Excepto para NULL, no tiene su propio objeto prototipo.
La importancia de un objeto prototipo es que si el objeto A es un prototipo del objeto B, el objeto B puede obtener todas las propiedades y métodos de objeto A. el objeto.getPrototypof se utiliza para obtener el objeto prototipo del objeto actual.
var p = object.getPrototypeOf (obj);
En el código anterior, el objeto P es el objeto prototipo del objeto obj.
El método Object.Create se utiliza para generar un nuevo objeto y heredar el objeto especificado.
var obj = object.create (p);
En el código anterior, el prototipo del objeto OBJ recién generado es el objeto p.
El atributo __proto__ no estándar (dos subrayos en el frente y detrás) puede reescribir el objeto prototipo de un determinado objeto. Sin embargo, debe intentar usar esta propiedad lo menos posible, pero use Object.GetPrototipof () y Object.SetPrototipof () para leer y escribir objetos prototipo.
var obj = {}; var p = {}; obj .__ proto__ = p; object.getPrototypeOf (obj) === P // VerdaderoEl código anterior establece el objeto P como el prototipo del objeto OBJ a través del atributo __proto__.
Aquí hay un ejemplo práctico.
var a = {x: 1}; var b = {__proto__: a}; bx // 1En el código anterior, el objeto B establece su objeto prototipo como un objeto a través del atributo __proto__, por lo que el objeto B puede obtener todas las propiedades y métodos de objeto a. El objeto B en sí mismo no tiene un atributo X, pero el motor JavaScript encuentra su objeto prototipo A a través del atributo __proto__, y luego lee el atributo X de a.
El nuevo comando crea un nuevo objeto de instancia a través de un constructor. Esencialmente está vinculando el prototipo del objeto de instancia a la propiedad prototipo del constructor, y luego ejecutando el constructor en el objeto de instancia.
var o = new foo (); // es equivalente a var o = nuevo objeto (); o .__ proto__ = foo.prototype; foo.call (o);
El atributo __proto__ propio del objeto prototipo también puede apuntar a otros objetos, formando así una "cadena prototipo" nivel por nivel.
var a = {x: 1}; var b = {__proto__: a}; var c = {__proto__: b}; cx // 1Cabe señalar que buscar un cierto atributo en la cadena prototipo tiene un impacto en el rendimiento. Cuanto mayor sea el nivel del objeto prototipo que está buscando, mayor será el impacto en el rendimiento. Si busca una propiedad inexistente, atravesará toda la cadena prototipo.
Esta acción apuntando
No importa dónde se define esto, cuando se usa, siempre apunta al objeto actual, no al objeto prototipo.
var o = {a: 2, m: function (b) {return this.a + 1; }}; var p = object.create (o); pa = 12; pm () // 13En el código anterior, el método m del objeto p proviene de su objeto prototipo o. En este momento, este objeto dentro del método M no apunta a O, sino a p.
Herencia de constructores
Esta sección introduce cómo hacer que un constructor herede otro constructor.
Suponga que hay un constructor de forma.
Function Shape () {this.x = 0; this.y = 0;} sape.prototype.move = function (x, y) {this.x += x; this.y += y; console.info ('Shape Moved');}; El constructor rectángulo hereda la forma. function rectangle () {sape.call (this); // llame al constructor de clase principal} // otra forma de escribir function rectangle () {this.base = shape; this.base ();} // La subclase hereda el método de clase principal rectangle.prototype = object.create (sape.prototype); rect.prototype.constructor = rectangle; var rect = new rectangle (); rect instancia de rectangle // tuerectoEl código anterior muestra que la herencia del constructor se divide en dos partes, una es que la subclase llama el método del constructor de la clase principal, y el otro es que el prototipo de la subclase apunta al prototipo de la clase principal.
En el código anterior, la subclase hereda la clase principal en su conjunto. A veces, solo se requiere la herencia de un solo método y se puede utilizar el siguiente método de escritura.
Classb.prototype.print = function () {classa.prototype.print.call (this); // algún código}En el código anterior, el método de impresión de la subclase B primero llama al método de impresión de la Clase A principal, y luego implementa su propio código. Esto es equivalente a heredar el método de impresión de la clase principal A.
__proto__ atributo
El atributo __proto__ apunta al objeto prototipo del objeto actual, es decir, el atributo prototipo del constructor.
var obj = new Object (); obj .__ proto__ === Object.prototype // trueObj .__ proto__ === obj.constructor.prototype // true
El código anterior primero crea un nuevo objeto obj, su atributo __proto__, apuntando al atributo prototipo del constructor (objeto u obj.constructor). Por lo tanto, después de comparar los dos, regrese verdadero.
Por lo tanto, hay tres formas de obtener el objeto prototipo del objeto de instancia obj.
Entre los tres métodos anteriores, los dos primeros no son muy confiables. El último estándar ES6 estipula que solo el navegador necesita implementar el atributo __proto__, y no se pueden implementar otros entornos. Sin embargo, obj.constructor.prototype puede fallar al cambiar manualmente el objeto prototipo.
var p = function () {}; var p = new P (); var c = function () {}; c.prototype = p; var c = new c (); c.constructor.prototype === P // falsoEn el código anterior, el objeto prototipo del constructor C se cambia a P, y el resultado es que C.Constructor.prototype está distorsionado. Por lo tanto, al cambiar el objeto prototipo, el atributo del constructor debe establecerse al mismo tiempo.
C.Prototype = P; C.Prototype.Constructor = C; C.Constructor.Prototype === P // Verdadero
Por lo tanto, se recomienda usar el tercer objeto. GetPrototypeOf Method para obtener el objeto prototipo. El uso de este método es el siguiente.
var o = new Object (); Object.getPrototypeOf (O) === Object.Prototype // True
Puede usar el método Object.getProTotypeOF para verificar si el navegador admite el atributo __proto__, que no es compatible con los navegadores antiguos.
Object.getProTotypeOf ({__proto__: null}) === NULLEl código anterior establece el atributo __proto__ de un objeto a NULL, y luego usa el método Object.getProTotypeOf para obtener el prototipo de este objeto para determinar si es igual a NULL. Si el entorno actual admite el atributo __proto__, el resultado de comparación de los dos debería ser verdadero.
Con el atributo __proto__, es fácil configurar el prototipo del objeto de instancia. Supongamos que hay tres objetos: máquina, vehículo y automóvil, donde la máquina es el prototipo del vehículo y el vehículo es el prototipo del automóvil, que se puede configurar con solo dos líneas de código.
vehículo .__ proto__ = máquina; automóvil .__ proto__ = vehículo;
El siguiente es un ejemplo. Las propiedades definidas en el objeto prototipo se leen respectivamente a través del atributo __proto__ y el atributo Constructor.Prototype.
Array.prototype.p = 'ABC'; var a = new Array (); a .__ Proto __. P // ABCA.Constructor.Prototype.p // ABC
Obviamente, __proto__ parece un poco más conciso.
Cuando se genera un objeto de instancia a través de un constructor, el atributo __proto__ del objeto de instancia apunta automáticamente al objeto prototipo del constructor.
var f = function () {}; var a = {}; f.prototype = a; var o = new f (); o .__ proto__ === a // trueHerencia de atributos
Hay dos tipos de atributos. Uno es el atributo nativo del objeto en sí, y el otro es el atributo heredado heredado del prototipo.
Propiedades nativas de un objeto
Todas las propiedades del objeto en sí se pueden obtener utilizando el método Object.getOwnPropertynames.
Object.getownPropertynames (fecha) // ["Parse", "Argumentos", "UTC", "Llamador", "Nombre", "Prototipo", "Ahora", "Longitud"]
Entre las propiedades del objeto en sí, algunas son enumerables (enumerables), mientras que otras no son enumerables. Solo obtenga aquellas propiedades que pueden enumerarse, use el método Object.Keys.
Object.Keys (fecha) // [] ASOWNProperty ()
El método de HaswnProperty devuelve un valor booleano para determinar si una determinada propiedad se define en el objeto en sí o en la cadena de prototipo.
Date.hasownproperty ('longitud') // triDate.hasownproperty ('toString') // falsoEl método de HaswnProperty es el único método en JavaScript que no atraviesa la cadena prototipo al procesar las propiedades del objeto.
Propiedades de herencia de un objeto
Los objetos creados con el método Object.Create heredarán las propiedades de todos los objetos prototipo.
var proto = {p1: 123}; var o = object.create (proto); o.p1 // 123o.hasownproperty ("p1") // falsoObtenga todos los atributos
Para determinar si un objeto tiene una determinada propiedad (si es propia o heredada), use el operador en.
"Longitud" en la fecha // Verdadero "Tostring" en la fecha // Verdadero
Obtenga todas las propiedades enumerables de un objeto (ya sea propio o heredado), y puede usar un bucle for-in.
var o1 = {p1: 123}; var o2 = object.create (o1, {p2: {valor: "ABC", enumerable: true}}); para (p en o2) {console.info (p);} // p2 // p2)Para obtener las propias propiedades del objeto en el For ... en bucle, puede usar el método de HaswnProperty para juzgar.
for (nombre var en objeto) {if (object.hasownproperty (name)) { / * bucle Code * /}}Para obtener todas las propiedades del objeto (ya sea propia o heredado, y si es enumerable), puede usar la siguiente función.
function herededpropertynames (obj) {var props = {}; while (obj) {object.getOwnPropertynames (obj) .forEach (function (p) {props [p] = true;}); obj = object.getPrototypeOf (obj); } return Object.getOwnPropertynames (Props);}El uso es el siguiente:
hereRedpropertynames (date) // ["llamado", "constructor", "toString", "utc", "call", "parse", "prototipo", "__definesetter__", "__lookupsetter__", "longitud", "argumentos", "vinculando", "__lookuptter__", "isProtype de", "tolocal", "tolocal", "tolocal", "tolocal "PropertyIsenumerable", "Valuef", "Aplicar", "__definegetter__", "Nombre", "Ahora", "HaswnProperty"]
Copia del objeto
Si desea copiar un objeto, debe hacer las siguientes dos cosas.
Asegúrese de que el objeto copiado tenga el mismo objeto prototipo que el objeto original.
Asegúrese de que el objeto copiado tenga las mismas propiedades que el objeto original.
La siguiente es la función de copiar el objeto escrito en función de los dos puntos anteriores.
función copyObject (orig) {var copy = object.create (object.getPrototypeOf (orig)); CopyOwnPropertiesFrom (Copy, Orig); return COPY;} function COPYOWNPROPERTIESFROM (Target, Source) {Object .getOwnPropertynames (fuente) .forEach (function (propkey) {var desc = object.getOwnPropertyDescriptor (fuente, propkey); objeto.defineProperty (target, propkey, desc);}); objetivo de retorno;}Herencia múltiple
JavaScript no proporciona múltiples funciones de herencia, es decir, no permite que un objeto herede múltiples objetos al mismo tiempo. Sin embargo, esta función se puede lograr a través de soluciones.
función m1 (prop) {this.hello = prop;} función m2 (prop) {this.world = prop;} function s (p1, p2) {this.base1 = m1; this.base1 (P1); this.base2 = m2; this.base2 (p2);} s.prototype = new M1 (); var s = new S (111, 222); S.Hello // 111s.World // 222En el código anterior, la subclase S hereda las clases de los padres M1 y M2. Por supuesto, desde la perspectiva de la cadena de herencia, S solo tiene una clase principal M1, pero dado que en la instancia de S, los constructores de M1 y M2 se ejecutan al mismo tiempo, hereda los métodos de estas dos clases al mismo tiempo.