Inheritância
Inheritância é o processo pelo qual um objeto pode ser baseado em outro. Isto permite que os objectos partilhem as propriedades uns dos outros.
Criei o protótipo Hero
e usei-o para criar um novo objecto chamado superman
. Mas nós não estamos fazendo nada com este objeto. Então vamos cuidar disso criando outra função chamada dialogue
.
function dialogue() {
console.log('I am ' + this.name);
}
Mas se rodarmos nosso código agora, nada vai acontecer porque esta função não sabe qual é o nome realmente. Para isso, precisamos de
I quero que esta nova função tenha as mesmas propriedades que a do Hero
. Ao invés de escrevê-las dentro desta função, podemos simplesmente dizer ao JavaScript para herdá-las do protótipo Hero
.
Isso é possível com a ajuda da propriedade prototype
que está disponível dentro de qualquer objeto em JavaScript.
Ao colocarmos dialogue
em Hero.prototype
, disponibilizamos a todas as instâncias de Hero
.
Diferencial Herança
JavaScript também vem com outro modelo de herança chamado “herança diferencial”. Neste modelo, os métodos não são copiados do pai para o filho. Mas em vez disso existe uma ligação entre os filhos e seu objeto pai.
Aqui, superman
não tem realmente seu próprio método chamado dialogue()
. Mas então como é que superman.dialogue()
funciona?
Quando o motor JavaScript se depara com superman.dialogue()
no código, procura a propriedade chamada dialogue
dentro do objecto superman
. Quando não encontrar uma, vai procurar a cadeia de protótipos até superman
do pai Hero.prototype
. Lá ele encontrará Hero.prototype.dialogue
e o chamará com um this
que é ligado a superman
.
Object.create()
Podemos tornar isto ainda mais exclusivo criando uma nova classe para Superman
que herdará as propriedades do protótipo de Hero
. Podemos fazer isso atribuindo o protótipo de Superman
ao protótipo de Hero
assim:
function Superman() {}
Superman.prototype = Hero.prototype
Mas o que isso faz é que ele apenas torna ambos Superman
e Hero
iguais. O que nós realmente precisamos é de um novo objeto que seja baseado no protótipo Hero
. Desde ES5, o JavaScript vem com uma função interna chamada Object.create()
. Vamos usá-la aqui como mostrado abaixo:
Superman.prototype = Object.create(Hero.prototype);
Isto irá criar um novo objeto vazio que é baseado no protótipo Hero
e atribuí-lo ao protótipo Superman
. Assim todas as propriedades que temos no protótipo Hero
podem agora ser acessadas pelo protótipo Superman
. Então ao invés de chamarmos new Hero
, podemos chamar new Superman
e tudo ainda funcionará como deveria.
Mas se você olhar mais de perto a saída, você notará que há um undefined
dentro dele. Isso porque atualmente o Hero
é um construtor somente para si mesmo. Temos de call
as propriedades de Hero
dentro do Superman
protótipo.
function Superman() {
Hero.call(this, 'Superman', 'Clark Kent', 'Krypton')
}
Vamos criar outro construtor chamado MarvelMovies
como mostrado abaixo:
function MarvelMovies(movieName, releaseYear) {
this.movieName = movieName;
this.releaseYear = releaseYear;
}
Quando uma função é usada como construtor, this
refere-se ao novo objecto que estamos a criar. Então neste construtor, eu tomei movieName
e releaseYear
como argumentos e atribuí esses valores aos movieName
e releaseYear
propriedades do nosso novo MarvelMovies
instância chamada avengers
.
var avengers = new MarvelMovies("avengers", 2012);
Vou então criar um novo método chamado output
para este protótipo como mostrado abaixo:
MarvelMovies.prototype.output = function() {
return "Movie: " + this.movieName + " Released in " + this.releaseYear;
}
console.log(avengers.output());
Future Inheritance
Um aspecto realmente grande da herança é que o JavaScript permite que você modifique ou expanda as características de uma classe mesmo depois de tê-la definido.
JavaScript irá procurar o protótipo ao tentar acessar propriedades em um objeto. Então, você pode alterar as classes em tempo de execução!
Para ilustrar isto, vamos criar um array como mostrado abaixo:
var numbers = ;
Array.prototype.shuffle = function() {
return this.sort(function() {
return Math.round( Math.random() * 2) - 1;
});
};
console.log(numbers.shuffle());
Aqui, o array numbers
existia antes do array Array.prototype.shuffle
existir. Mas no JavaScript, as pesquisas de propriedades sobem na cadeia de protótipos. É por isso que o array ainda tem acesso ao novo método shuffle
, já que ele existe no Array.prototype
quando estamos realmente tentando usá-lo.
Em termos simples, nós criamos um array, então voltamos e damos acesso a todos os Arrays a um novo método.