Embora o JavaScript seja uma linguagem orientada a objetos, seu mecanismo de herança era diferente de outros idiomas tradicionais orientados a objetos desde a sua criação. É um mecanismo de herança baseado em protótipo. No entanto, sob esse mecanismo, ainda existem alguns métodos diferentes de implementação para herança.
Método 1: Herança clássica
A chamada herança de classe refere-se a imitar o método de herança dos idiomas tradicionais orientados a objetos. Tanto a herança quanto as partes herdadas são "classes". O código é o seguinte:
Primeiro defina uma classe pai (ou superclasse):
função pessoa (nome) {this.name = name; } Pessoa.prototype.getName = function () {return this.name; };Os atributos da pessoa da classe pai são definidos no construtor, o que pode garantir que o atributo de nome da subclasse herde, ele não compartilha esse atributo com ele, mas pertence à subclasse separadamente. O método getName é montado no protótipo para permitir várias instâncias da subclasse herdando -o para compartilhar esse corpo de método, para que a memória possa ser salva (para várias instâncias, toda vez que uma instância de novo será lançada, garantirá que o método GetName dessas instâncias se referam ao mesmo espaço de memória, em vez de um espaço independente).
Defina um método de herança se estende, como segue:
função estend (subclasse, 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; }}Neste método, primeiro crie uma nova classe F, deixe seu protótipo ser o protótipo da classe pai e deixar o protótipo do ponto de subclasse para uma instância da classe F, alcançando assim o objetivo de herdar a classe pai. Ao mesmo tempo, como o protótipo da subclasse é modificado, o atributo construtor do protótipo modificado é apontado para a subclasse, para que ele tenha uma função construtora e, ao mesmo tempo, a subclasse pode montar um atributo de superclasse. A subclasse pode ligar para a classe pai através desta propriedade, estabelecendo assim o relacionamento entre a subclasse e a classe pai.
Defina um autor de subclasse para herdar a pessoa da classe pai, como segue:
Autor da função (nome, livros) {Author.superclass.constructor.call (este, nome); this.book = livros; } estender (autor, pessoa); Author.Prototype.GetBooks = function () {return this.book; }Aqui, o construtor da classe pai é chamado através de seu atributo de superclasse no construtor da subclasse. Ao mesmo tempo, o método de chamada é usado para converter este ponteiro da chamada do método, para que o autor da subclasse também tenha (herda) as propriedades da classe pai e a subclasse também possui seu próprio livro de atributos. Portanto, os livros de parâmetros são atribuídos ao livro de atributos no construtor para alcançar o objetivo da construção. Use a função de extensão para herdar as propriedades e métodos no protótipo da pessoa da classe pai (na verdade, apenas os métodos são herdados, porque apenas montamos os métodos para o protótipo antes e as propriedades são definidas no construtor). Ao mesmo tempo, o autor possui seu próprio método getbooks, montando -o no protótipo correspondente, alcançando o objetivo de se expandir ainda mais com base na herança.
Esse método de herança é obviamente uma herança de tipo semelhante à linguagem tradicional orientada a objetos. A vantagem é que é fácil para programadores que estão acostumados ao conceito tradicional orientado a objetos. A desvantagem é que o processo é relativamente pesado e o consumo de memória é um pouco maior, porque a subclasse também possui seu próprio construtor e protótipo, e os atributos da subclasse e da classe pai estão completamente isolados. Mesmo que os dois tenham o mesmo valor, eles não podem compartilhar a mesma memória.
Método 2: Herança de protótipo
Primeiro, defina uma classe pai. Aqui não vamos imitar deliberadamente o uso de construtores para defini -lo, mas definiremos diretamente um objeto na forma de literais de objeto, que é a classe pai
var pessoa = {nome: 'Nome padrão', getName: function () {return this.name; }};Como o primeiro método, o objeto possui um nome de propriedade e um método getName.
Em seguida, defina um método de clonagem para implementar a herança da subclasse para a classe pai, como segue:
função clone (obj) {função f () {} f.prototype = obj; retornar novo f (); }O método de clonagem cria um novo objeto, aponta o protótipo do objeto para a classe pai, ou seja, o parâmetro OBJ e retorna o objeto ao mesmo tempo.
Finalmente, a subclasse herda a classe dos pais através da função de clonagem, como segue:
var autor = clone (pessoa); Autor.book = ['javascript']; Autor.Showbook = function () {return this.book; }Aqui é definida uma subclasse e a pessoa da classe pai é herdada através da função clone, e um livro de atributos é expandido e um showbook de método é expandido. Aqui, a subclasse também possui o nome do atributo, mas é o mesmo que o valor do nome da classe pai, para que não seja substituído. Se for diferente, você pode usá -lo.
Autor.name = 'novo nome'; Substituir esta propriedade para obter um novo valor de atributo de nome da subclasse.
Essa herança do protótipo é mais simples e mais natural que a herança de classe. Ao mesmo tempo, se os atributos da subclasse e os valores dos atributos da classe pai forem os mesmos e puderem ser modificados, eles realmente compartilham o mesmo espaço de memória. Por exemplo, o atributo de nome acima é difícil de entender para programadores que estão acostumados aos programas tradicionais orientados a objetos. Se os dois forem escolhidos, esse método é sem dúvida melhor.
Como o JavaScript adota uma abordagem baseada em protótipo para implementar a herança, e o protótipo de cada objeto só pode apontar para uma instância de uma classe específica (não para várias instâncias), como implementar a herança múltipla (ou seja, permitir que uma classe tenha métodos e atributos de várias classes ao mesmo tempo, e não define esses métodos e atributos internos)?
No padrão de design JavaScript, é dada uma classe de mixin:
Primeiro, defina uma classe de doping para salvar alguns métodos e atributos comumente usados. Esses métodos e atributos podem ser adicionados a qualquer outra classe por meio de expansão, para que a classe adicionada tenha certos métodos e atributos da classe. Se várias classes de doping forem definidas e adicionadas a uma classe ao mesmo tempo, a classe implementa indiretamente a "herança múltipla". Com base nessa idéia, a implementação é a seguinte:
Definição de classe dominante de elemento:
var mixin = function () {}; Mixin.prototype = {serialize: function () {var output = []; para (chave nisso) {output.push (chave+":"+this [chave]); } return Output.Join (','); }}A classe de doping possui um método serializador usado para percorrer a si mesma, produzir seus próprios atributos e valores de atributo e retorná -los como strings, separados por vírgulas.
Defina um método de expansão para fazer uma classe ter atributos ou métodos de uma classe de vários grupos após a expansão, como segue:
Função Aument (Receiveclass, GiveClass) {if (Argumentos [2]) {for (var i = 2, len = argumentos.length; i <len; i ++) {recebendoclass.prototype [argumentos [i]] = giveclass.prototypes [i]]; }} else {for (MethodName em GiveClass.Prototype) {if (! Receiveclass.prototype [MethodName]) {receivingclass.prototype [MethodName] = GiveClass.Prototype [MethodName]; }}}}Este método possui dois parâmetros por padrão. O primeiro parâmetro aceita a classe expandida, o segundo parâmetro é a classe dopada (usada para expandir outras classes) e pode haver outros parâmetros. Se for maior que dois parâmetros, os parâmetros subsequentes são nomes de método ou atributo, que são usados para indicar que a classe expandida deseja herdar os atributos ou métodos especificados da classe dopada. Caso contrário, todos os atributos e métodos da classe dopada são herdados por padrão. Nesta função, a primeira ramificação se é usada para herdar os atributos e métodos especificados, e a ramificação else é o caso em que todos os atributos e métodos são herdados por padrão. A essência deste método é expandir (adicionar) as propriedades e métodos no protótipo da classe de doping de elemento ao protótipo da classe expandida, para que possua propriedades e métodos da classe de doping de elemento.
Finalmente, use o método de expansão para alcançar a herança múltipla
Augment (autor, Mixin); var autor = novo autor ('js', ['Javascript Design Patterns']); alerta (autor.Serialize ());Aqui está uma classe de autor. Esta classe herda da classe pai da pessoa e também possui métodos e propriedades da mixina de classe metabolizada. Se quiser, você pode definir n classes metabolizadas para expandir a classe. Também pode herdar as propriedades e métodos de outras classes metabolizadas que você define, para que a herança múltipla seja realizada. Finalmente, o resultado da operação do método serialize do autor é o seguinte:
Você descobrirá que esta classe possui as propriedades e os métodos da classe de pessoa, classe do autor e classe de mixin. As propriedades e métodos de pessoa e mixina são todos obtidos por meio da "herança". De fato, realiza herança múltipla.