Aunque JavaScript es un lenguaje orientado a objetos, su mecanismo de herencia era diferente de otros idiomas tradicionales orientados a objetos desde su inicio. Es un mecanismo de herencia basado en prototipos. Sin embargo, bajo este mecanismo, todavía hay algunos métodos de implementación diferentes para la herencia.
Método 1: Herencia clásica
La llamada herencia de clase se refiere a imitar el método de herencia de los idiomas tradicionales orientados a objetos. Tanto la herencia como las partes heredadas son "clases". El código es el siguiente:
Primero defina una clase madre (o superclase):
Función Persona (nombre) {this.name = name; } Persona.prototype.getName = function () {return this.name; };Los atributos de la persona de la clase principal se definen en el constructor, lo que puede garantizar que el atributo de nombre de la subclase heredalo no comparte este atributo con él, sino que pertenece a la subclase por separado. El método GetName se monta en el prototipo para permitir múltiples instancias de la subclase que lo herede para compartir este cuerpo del método, de modo que la memoria se pueda guardar (para múltiples instancias, cada vez que salga una instancia de nueva, asegurará que el método GetName de estas instancias se refiera al mismo espacio de memoria, en lugar de un espacio independiente).
Definir un método de herencia se extiende, como sigue:
function extend (subclass, superclass) {var f = function () {}; F.prototype = superclass.prototype; subclass.prototype = new f (); subclass.prototype.constructor = subclass; subclass.superclass = superclass.prototype; if (superclass.prototype.constructor == object.prototype.constructor) {superclass.prototype.constructor = superclass; }}En este método, primero cree una nueva clase F, que su prototipo sea el prototipo de la clase principal, y deje que el prototipo de la subclase apunte a una instancia de la Clase F, lo que alcanza el propósito de heredar la clase principal. Al mismo tiempo, dado que se modifica el prototipo de la subclase, el atributo de constructor del prototipo modificado apunta a la subclase, de modo que tenga una función de constructor, y al mismo tiempo, la subclase puede montar un atributo de superclase. La subclase puede llamar a la clase principal a través de esta propiedad, estableciendo así la relación entre la subclase y la clase principal.
Defina a un autor de subclase para heredar a la persona de la clase principal, de la siguiente manera:
Función Autor (nombre, libros) {autor.superclass.constructor.call (this, nombre); this.book = libros; } extender (autor, persona); Autor.prototype.getBooks = function () {return this.book; }Aquí, el constructor de la clase principal se llama a través de su atributo de superclase en el constructor de la subclase. Al mismo tiempo, el método de llamada se utiliza para convertir este puntero de la llamada del método, de modo que el autor de subclase también tenga (heredera) las propiedades de la clase principal, y la subclase también tiene su propio libro de atributos. Por lo tanto, los libros de parámetros se asignan al libro de atributos en el constructor para lograr el propósito de la construcción. Use la función Extensión para heredar las propiedades y métodos en el prototipo de la persona de la clase principal (en realidad, solo los métodos se heredan, porque acabamos de montar los métodos al prototipo antes, y las propiedades se definen en el constructor). Al mismo tiempo, el autor tiene su propio método GetBooks, montándolo en el prototipo correspondiente, logrando el propósito de expandirse aún más sobre la base de la herencia.
Este método de herencia es obviamente una herencia de tipo similar al lenguaje tradicional orientado a objetos. La ventaja es que es fácil para los programadores que están acostumbrados al concepto tradicional orientado a objetos. La desventaja es que el proceso es relativamente engorroso y el consumo de memoria es ligeramente mayor, porque la subclase también tiene su propio constructor y prototipo, y los atributos de la subclase y la clase principal están completamente aislados. Incluso si los dos son del mismo valor, no pueden compartir la misma memoria.
Método 2: herencia prototipo
Primero, defina una clase principal. Aquí no imitaremos deliberadamente el uso de constructores para definirlo, sino que definiremos directamente un objeto en forma de literales de objetos, que es la clase principal
var persona = {nombre: 'nombre predeterminado', getName: function () {return this.name; }};Al igual que el primer método, el objeto tiene un nombre de propiedad y un método GetName.
Luego, defina un método de clonación para implementar la herencia de la subclase a la clase principal, de la siguiente manera:
function clone (obj) {function f () {} f.prototype = obj; devolver nuevo f (); }El método de clonación crea un nuevo objeto, señala el prototipo del objeto a la clase principal, es decir, el parámetro obj, y devuelve el objeto al mismo tiempo.
Finalmente, la subclase hereda la clase principal a través de la función de clonación, como sigue:
var autor = clone (persona); Autor.book = ['javaScript']; Autor.showbook = function () {return this.book; }Aquí se define una subclase, y la persona de la clase principal se hereda a través de la función clon, y se expande un libro de atributos, y se expande un mechón de método. Aquí, la subclase también tiene el nombre del atributo, pero es el mismo que el valor de nombre de la clase principal, por lo que no se anula. Si es diferente, puede usarlo.
Autor.name = 'nuevo nombre'; Sobrescribe esta propiedad para obtener un nuevo valor de atributo de nombre de la subclase.
Esta herencia prototipo es más simple y más natural que la herencia de clase. Al mismo tiempo, si los atributos de la subclase y los valores de los atributos de la clase principal son los mismos y pueden modificarse, entonces realmente comparten el mismo espacio de memoria. Por ejemplo, el atributo de nombre anterior es difícil de entender para los programadores que están acostumbrados a los programas tradicionales orientados a objetos. Si se eligen los dos, este método es indudablemente mejor.
Dado que JavaScript adopta un enfoque basado en prototipos para implementar la herencia, y el prototipo de cada objeto solo puede apuntar a una instancia de una clase específica (no a múltiples instancias), ¿cómo implementar múltiples herencias (es decir, que una clase tenga métodos y atributos de múltiples clases al mismo tiempo, y no define estos métodos y atributos a sí mismos internamente)?
En el patrón de diseño de JavaScript, se da una clase de mezcla:
Primero, defina una clase de dopaje para guardar algunos métodos y atributos de uso común. Estos métodos y atributos se pueden agregar a cualquier otra clase a través de la expansión, de modo que la clase agregada tiene ciertos métodos y atributos de la clase. Si se definen y se agregan múltiples clases de dopaje y se agregan a una clase al mismo tiempo, entonces la clase implementa indirectamente "herencia múltiple". Según esta idea, la implementación es la siguiente:
Definición de clase dominante de elementos:
var mixin = function () {}; Mixin.prototype = {serialize: function () {var output = []; para (clave en esto) {output.push (clave+":"+esta [clave]); } return output.Join (','); }}La clase de dopaje tiene un método de serialización utilizado para atravesarlo, producir sus propios atributos y valores de atributos, y devolverlos como cadenas, separados por comas.
Definir un método de expansión para hacer que una clase tenga atributos o métodos de una clase multigrupo después de la expansión, de la siguiente manera:
Function Augment (recibeClass, dandoClass) {if (argumentos [2]) {for (var i = 2, len = arguments.length; i <len; i ++) {receptorClass.prototype [argumentos [i]] = dandoClass.prototype [argumentos [i]]; }} else {for (MethodName in DiningClass.prototype) {if (! ReceptiveClass.prototype [MethodName]) {ReceptivingClass.Prototype [MethodName] = dedClass.Prototype [MethodName]; }}}}Este método tiene dos parámetros de forma predeterminada. El primer parámetro acepta la clase expandida, el segundo parámetro es la clase dopada (utilizada para expandir otras clases), y puede haber otros parámetros. Si es mayor que dos parámetros, los parámetros posteriores son los nombres de métodos o atributos, que se utilizan para indicar que la clase ampliada quiere heredar los atributos o métodos especificados de la clase dopada. De lo contrario, todos los atributos y métodos de la clase dopada se heredan de forma predeterminada. En esta función, la primera rama IF se usa para heredar los atributos y métodos especificados, y la rama de lo contrario es el caso donde todos los atributos y métodos se heredan de forma predeterminada. La esencia de este método es expandir (agregar) las propiedades y métodos en el prototipo de la clase de dopaje de elementos al prototipo de la clase expandida, para que tenga propiedades y métodos de la clase de dopaje de elementos.
Finalmente, use el método de expansión para lograr una herencia múltiple
Aumento (autor, mixin); var autor = nuevo autor ('js', ['JavaScript Design Patterns']); alerta (autor.serialize ());Aquí hay una clase de autor. Esta clase hereda de la clase principal de la persona y también tiene métodos y propiedades de la mezcla de clase metabolizada. Si lo desea, puede definir N clases metabolizadas para expandir la clase. También puede heredar las propiedades y métodos de otras clases metabolizadas que define, de modo que se realice una herencia múltiple. Finalmente, el resultado de la operación del método de serialización del autor es el siguiente:
Encontrará que esta clase tiene las propiedades y métodos de la clase de persona, clase de autor y clase MIXIN. Las propiedades y métodos de persona y mixin se obtienen a través de la "herencia". De hecho, se da cuenta de la herencia múltiple.