If you're seeing this message, it means we're having trouble loading external resources on our website.

Se você está atrás de um filtro da Web, certifique-se que os domínios *.kastatic.org e *.kasandbox.org estão desbloqueados.

Conteúdo principal

Revisão: Modelo Orientado a Objetos

Esta é uma revisão do que abordamos nesse tutorial sobre o modelo orientado a objetos.
Quando nós criamos programas, frequentemente descobrimos que queremos criar muitos objetos os quais todos compartilham propriedades parecidas - como muitos gatos, que têm a cor do pelo ou o tamanho levemente diferentes, ou muitos botões, com diferentes rótulos e posições. Nós queremos poder dizer "isto é o que geralmente um gato é" e então dizer "vamos criar esse gato específico e esse outro gato, e eles serão parecidos em algumas formas e diferentes em outras formas também." Nesse caso, nós queremos usar um modelo orientado a objetos para definir os tipos de objetos e criar novas instâncias de tais objetos.
Para definir um tipo de objeto em JavaScript, nós primeiro temos que definir uma "função construtora". Essa é a função que nós iremos usar sempre que quisermos criar uma nova instância desse tipo de objeto. Aqui está uma função construtora para o tipo de objeto Book:
var Book = function(title, author, numPages) {
  this.title = title;
  this.author = author;
  this.numPages = numPages;
  this.currentPage = 0;
};
A função recebe argumentos para os aspectos que serão diferentes para cada livro - o título, autor e número de páginas. Ela então atribui as propriedades iniciais do objeto baseada nesses argumentos, usando a palavra-chave this. Quando usamos this em um objeto, estamos nos referindo à atual instância de um objeto, referindo-se a ele mesmo. Nós precisamos guardar as propriedades em this para garantir que possamos nos lembrar delas futuramente.
Para criar uma instância de um objeto Book, nós declaramos a nova variável para armazená-lo, então usamos a palavra-chave new, seguida pela função construtora, e passamos os argumentos de entrada que o construtor espera:
var book = new Book("Robot Dreams", "Isaac Asimov", 320);
Podemos então acessar qualquer propriedade que armazenamos no objeto usando a notação ponto:
println("I loved reading " + book.title); // I loved reading Robot Dreams
println(book.author + " is my fav author"); // "Isaac Asimov" is my fav author
Vamos examinar isso por um minuto, e mostrar o que teria acontecido se não definíssemos nossa função construtora corretamente:
var Book = function(title, author, numPages) {
};
var book = new Book("Little Brother", "Cory Doctorow", 380);
println("I loved reading " + book.title); // I loved reading undefined
println(book.author + " is my fav author"); // undefined is my favorite author
Se passarmos os argumentos para a função construtora, mas não os guardarmos explicitamente na this, então não poderemos acessá-los depois! O objeto terá se esquecido deles há muito tempo.
Quando definimos tipos de objeto, muitas vezes queremos associar não só propriedades como também comportamentos neles - equivalente a todos nossos objetos do tipo cat serem capazes dos comportamentos meow() e eat(). Portanto precisamos ser capazes de atribuir funções para as nossas definições de tipos de objetos, e nós podemos fazer isso definindo-os no que é chamado de object prototype - objeto protótipo:
Book.prototype.readItAll = function() {
  this.currentPage = this.numPages;
  println("You read " + this.numPages + " pages!");
};
É similar a como definiríamos uma função normalmente, exceto que nós deixamos o protótipo Book pendurado em vez de simplesmente defini-lo globalmente. Essa é a maneira que o JavaScript sabe que é uma função que pode ser chamada em qualquer objeto Book, e que essa função deveria ter acesso ao this chamado dentro do objeto book.
Podemos chamar a função (a qual chamamos de um método, já que ela está atribuída para um objeto), da seguinte forma:
var book = new Book("Animal Farm", "George Orwell", 112);
book.readItAll(); // You read 112 pages!
Lembre-se, o objetivo do design orientado a objeto é facilitar para nós a criação de múltiplos objetos relacionados (instâncias de objetos). Vamos ver isso no código:
var pirate = new Book("Pirate Cinema", "Cory Doctorow", 384);
var giver = new Book("The Giver", "Lois Lowry", 179);
var tuck = new Book("Tuck Everlasting", "Natalie Babbit", 144);

pirate.readItAll(); // You read 384 pages!
giver.readItAll(); // You read 179 pages!
tuck.readItAll(); // You read 144 pages!
Este código nos mostra três livros similares - todos têm os mesmos tipos de propriedades e comportamentos, mas são diferentes. Legal!
Agora, se você pensar sobre o mundo real, gatos e cães são diferentes tipos de objetos, então você provavelmente iria criar diferentes tipos de objetos para eles se você estivesse programando um Gato e um Cão. Um gato iria miar(), um cachorro iria latir(). Mas eles também são similares, tanto o gato como o cão iria comer(), ambos teriam uma idade, um nascimento e uma morte. Ambos são mamíferos, e isso significa que eles compartilham uma grande quantidade de coisas em comum, mesmo sendo animais diferentes.
Nesse caso, nós queremos usar a ideia de herança de objeto. Um tipo de objeto pode herdar propriedades e comportamentos de um objeto pai, mas também tem suas próprias coisas únicas referentes a ele mesmo. Todos os Gatoss e Cãos podem herdar de Mamífero, a fim de que eles não tenham que inventar comer() do zero. Como faríamos isso em JavaScript?
Voltemos ao nosso exemplo do livro, e digamos que Book é o tipo de objeto "pai", e nós queremos criar dois tipos de objetos que herdam dele - Paperback (livro impresso) e EBook (livro eletrônico).
Um livro impresso é igual a um livro, mas tem uma diferença principal, pelo menos em nosso programa: ele tem uma imagem na capa. Portanto, nosso construtor precisa receber quatro argumentos para receber essa informação extra:
var PaperBack = function(title, author, numPages, cover) {
  // ...
}
Agora, não queremos ter de refazer todo o trabalho que já fizemos no construtor Book para recordarmos aqueles três primeiros argumentos - queremos tirar vantagem do fato que o código para isso poderia ser o mesmo. Podemos, na realidade, chamar o construtor do Book a partir construtor do PaperBack e passar os argumentos:
var PaperBack = function(title, author, numPages, cover) {
  Book.call(this, title, author, numPages);
  // ...
};
Entretanto, ainda precisamos armazenar a propriedade cover no objeto, então precisamos de mais uma linha para cuidar disso:
var PaperBack = function(title, author, numPages, cover) {
  Book.call(this, title, author, numPages);
  this.cover = cover;
};
Agora, temos um construtor para nosso PaperBack, o que o ajuda a compartilhar as mesmas propriedades como Book, mas também queremos que nosso PaperBack herde seus métodos. Aqui está como fazemos isso, dizendo ao programa que o protótipo PaperBack deve ser baseado no protótipo Book:
PaperBack.prototype = Object.create(Book.prototype);
Também podemos anexar um comportamento específico para o livro impresso, como poder queimá-lo, e podemos fazer isso definindo funções no protótipo, depois da linha acima:
PaperBack.prototype.burn = function() {
  println("Omg, you burnt all " + this.numPages + " pages");
  this.numPages = 0;
};
Agora podemos criar um novo livro impresso, lê-lo e queimá-lo!
var calvin = new PaperBack("The Essential Calvin & Hobbes", "Bill Watterson", 256, "http://ecx.images-amazon.com/images/I/61M41hxr0zL.jpg");

calvin.readItAll(); // Você lê 256 páginas!
calvin.burn(); // Meu Deus, você queimou todas as 256 páginas!
(Bem, não vamos queimá-lo de verdade, porque esse é um livro muito bom, mas, talvez fizéssemos isso se estivéssemos presos em um deserto glacial e desesperados por calor e prestes a morrer.)
Agora, você viu como podemos usar os princípios do modelo orientado a objetos em JavaScript para criar dados mais complexos para seus programas e modelar melhor os mundos criados com programação.

Quer participar da conversa?

Você entende inglês? Clique aqui para ver mais debates na versão em inglês do site da Khan Academy.