diff options
Diffstat (limited to 'files/pt-br/web/javascript/reference/classes/index.html')
-rw-r--r-- | files/pt-br/web/javascript/reference/classes/index.html | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/files/pt-br/web/javascript/reference/classes/index.html b/files/pt-br/web/javascript/reference/classes/index.html new file mode 100644 index 0000000000..62f5d0270f --- /dev/null +++ b/files/pt-br/web/javascript/reference/classes/index.html @@ -0,0 +1,364 @@ +--- +title: Classes +slug: Web/JavaScript/Reference/Classes +tags: + - Classes + - Constructor + - ECMAScript6 + - Herança + - Intermediário + - JavaScript +translation_of: Web/JavaScript/Reference/Classes +--- +<div>{{JsSidebar("Classes")}}</div> + +<p>Classes em JavaScript são introduzidas no ECMAScript 2015 e são simplificações da linguagem para as heranças baseadas nos protótipos. A sintaxe para classes <strong>não</strong> introduz um novo modelo de herança de orientação a objetos em JavaScript. Classes em JavaScript provêm uma maneira mais simples e clara de criar objetos e lidar com herança.</p> + +<h2 id="Definindo_classes">Definindo classes</h2> + +<p>As Classes são, de fato, "funções especiais", e, assim como você pode definir <a href="https://wiki.developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/function">"function expressions"</a> e <a href="https://wiki.developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Statements/function">"function declarations"</a>, a sintaxe de uma classe possui dois componentes: <a href="/en-US/docs/Web/JavaScript/Reference/Operators/class">"class expressions</a>" e <a href="/en-US/docs/Web/JavaScript/Reference/Statements/class">"class declarations"</a>.</p> + +<h3 id="Declarando_classes">Declarando classes</h3> + +<p>Uma maneira de definir uma classe é usando uma declaração de classe. Para declarar uma classe, você deve usar a palavra-chave <code>class</code> seguida pelo nome da classe (aqui "Retangulo").</p> + +<pre class="brush: js">class Retangulo { + constructor(altura, largura) { + this.altura = altura; + this.largura = largura; + } +}</pre> + +<h4 id="Uso_antes_da_declaração_Hoisting_-_Tradução_Literal_Lançamento">Uso antes da declaração (Hoisting - Tradução Literal: Lançamento)</h4> + +<p>Uma diferença importante entre <strong>declarações de funções</strong> das <strong>declarações de classes</strong>, é que declararações de funções são {{Glossary("Hoisting", "hoisted")}} e declarações de classes não são. Primeiramente deve declarar sua classe para só então acessá-la, pois do contrário o código a seguir irá lançar uma exceção: {{jsxref("ReferenceError")}}:</p> + +<pre class="brush: js example-bad">const p = new Retangulo(); // Erro de referência (ReferenceError) + +class Retangulo {} +</pre> + +<h3 id="Expressões_de_Classes">Expressões de Classes</h3> + +<p>Uma <strong>Expressão de Classe</strong> (class expression) é outra forma para definir classes. Expressões de Classes podem possuir nomes ou não (anônimas). O nome dado para uma expressão de classe é local ao corpo da classe.</p> + +<pre class="brush: js">// sem nome +let Retangulo = class { + constructor(altura, largura) { + this.altura = altura; + this.largura = largura; + } +}; + +// nomeada +let Retangulo = class Retangulo { + constructor(altura, largura) { + this.altura = altura; + this.largura = largura; + } +}; +</pre> + +<p><strong>Nota:</strong> As <strong>expressões de classe</strong> também sofrem com o mesmo problema de {{Glossary("Hoisting", "hoisted")}} mencionados em <strong>declarações </strong>de classe.</p> + +<h2 id="Corpo_de_uma_classe_e_definições_de_métodos">Corpo de uma classe e definições de métodos</h2> + +<p>O corpo de uma classe é a parte que está entre chaves <code>{}</code>. É aí onde você define os membros da classe, como os métodos, ou os construtores.</p> + +<h3 id="Modo_Estrito_strict_mode">Modo Estrito (strict mode)</h3> + +<p>Os corpos das Declarações de Classes e das Expressões de Classes são executados em <a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Strict_mode">modo estrito</a>.</p> + +<h3 id="Construtor">Construtor</h3> + +<p>O método <code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/constructor">constructor</a></code> é um tipo especial de método para criar e iniciar um objeto criado pela classe. Só pode existir um método especial com o nome "constructor" dentro da classe. Um erro de sintáxe {{jsxref("SyntaxError")}} será lançado se a classe possui mais do que uma ocorrência do método <code>constructor</code>.</p> + +<p>Um construtor pode usar a palavra-chave <code>super</code> para chamar o construtor de uma classe pai.</p> + +<h3 id="Métodos_Protótipos">Métodos Protótipos</h3> + +<p>Veja também <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions">definições de métodos (method definitions)</a>.</p> + +<pre class="brush: js">class Retangulo { + constructor(altura, largura) { + this.altura = altura; this.largura = largura; + } + //Getter + get area() { + return this.calculaArea() + } + + calculaArea() { + return this.altura * this.largura; + } +} + +const quadrado = new Retangulo(10, 10); + +console.log(quadrado.area);</pre> + +<h3 id="Métodos_estáticos">Métodos estáticos</h3> + +<p>A palavra-chave <code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/static">static</a></code> define um método estático de uma classe. Métodos estáticos são chamados sem a instanciação da sua classe e não podem ser chamados quando a classe é instanciada. Métodos estáticos são geralmente usados para criar funções de utilidades por uma aplicação.</p> + +<pre class="brush: js">class Ponto { + constructor(x, y) { + this.x = x; + this.y = y; + } + + static distancia(a, b) { + const dx = a.x - b.x; + const dy = a.y - b.y; + + return Math.hypot(dx, dy); + } +} + +const p1 = new Ponto(5, 5); +const p2 = new Ponto(10, 10); + +p1.distancia; //undefined +p2.distancia; //undefined + +console.log(Ponto.distancia(p1, p2));</pre> + +<h3 id="Empacotando_com_protótipos_e_métodos_estáticos">Empacotando com protótipos e métodos estáticos</h3> + +<p>Quando um método estático ou protótipo é chamado sem um objeto "this" configurado (ou com "this" como boolean, string, number, undefined ou null), então o valor "this" será <strong><code>undefined</code></strong> dentro da função chamada. Autoboxing não vai acontecer. O comportamento será o mesmo mesmo se escrevemos o código no modo não-estrito.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">class</span> <span class="class-name token">Animal</span> <span class="punctuation token">{</span> + falar<span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">return</span> <span class="keyword token">this</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + <span class="keyword token">static</span> comer<span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">return</span> <span class="keyword token">this</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> +<span class="punctuation token">}</span> + +<span class="keyword token">let</span> obj <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Animal</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">; +obj.falar(); // Animal {}</span> +<span class="keyword token">let</span> falar <span class="operator token">=</span> obj<span class="punctuation token">.</span>falar<span class="punctuation token">;</span> +falar<span class="punctuation token">()</span><span class="punctuation token">;</span> <span class="comment token">// undefined</span> + +Animal.comer(); // class Animal +<span class="keyword token">let</span> comer <span class="operator token">=</span> Animal<span class="punctuation token">.</span>comer<span class="punctuation token">;</span> +<span class="function token">comer</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="comment token">// undefined</span></code></pre> + +<p>Se escrevemos o código acima usando classes baseadas em função tradicional, então o autoboxing acontecerá com base no valor de "this" para o qual a função foi chamada.</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js"><span class="keyword token">function</span> <span class="function token">Animal</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="punctuation token">}</span> + +Animal<span class="punctuation token">.</span>prototype<span class="punctuation token">.</span>falar <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">return</span> <span class="keyword token">this</span><span class="punctuation token">;</span> +<span class="punctuation token">}</span> + +Animal<span class="punctuation token">.</span>comer <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">return</span> <span class="keyword token">this</span><span class="punctuation token">;</span> +<span class="punctuation token">}</span> + +<span class="keyword token">let</span> obj <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Animal</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="keyword token">let</span> falar <span class="operator token">=</span> obj<span class="punctuation token">.</span>falar<span class="punctuation token">;</span> +falar<span class="punctuation token">()</span><span class="punctuation token">;</span> <span class="comment token">// objeto global</span> + +<span class="keyword token">let</span> comer <span class="operator token">=</span> Animal<span class="punctuation token">.</span>comer<span class="punctuation token">;</span> +comer<span class="punctuation token">()</span><span class="punctuation token">;</span> <span class="comment token">// objeto global</span></code></pre> + +<h3 id="Propriedades_de_instância">Propriedades de instância</h3> + +<p>Propriedades de instâncias devem ser definidas dentro dos métodos da classe:</p> + +<pre><code>class Retangulo { + constructor(altura, largura) { + this.altura = altura; + this.largura = largura; + } +}</code> +</pre> + +<p>Propriedades de dados estáticos e propriedades de dados prototipados (prototype) devem ser definidos fora da declaração do corpo da classe.</p> + +<pre><code>Retangulo.larguraEstatico = 20; +Retangulo.prototype.larguraPrototipagem = 25;</code></pre> + +<h2 id="Sub_classes_com_o_extends">Sub classes com o <code>extends</code></h2> + +<p>A palavra-chave <code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/extends">extends</a></code> é usada em uma <em>declaração de classe</em>, ou em uma <em>expressão de classe </em>para criar uma classe como filha de uma outra classe.</p> + +<pre class="brush: js">class Animal { + constructor(nome) { + this.nome = nome; + } + + falar() { + console.log(this.nome + ' emite um barulho.'); + } +} + +class Cachorro extends Animal { + falar() { + console.log(this.nome + ' latidos.'); + } +} + +<code class="language-js"><span class="keyword token">let</span> cachorro <span class="operator token">=</span> <span class="keyword token">new</span> </code>Cachorro<code class="language-js"><span class="punctuation token">(</span><span class="string token">'Mat'</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +cachorro<span class="punctuation token">.</span></code>falar<code class="language-js"><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code> +</pre> + +<p>Se existir um contrutor nas subclasses, é necessário primeiro chamar super() antes de usar a keyword "this".</p> + +<p>Também é possivel ampliar (extends) "classes" baseadas em funções tradicionais.</p> + +<pre class="brush: js">function Animal (nome) { + this.nome = nome; +} + +Animal.prototype.falar = function() { + console.log(this.nome + ' faça barulho.'); +} + +class Cachorro extends Animal { + falar() { + console.log(this.nome + ' lati.'); + } +} + +let cachorro = new Cachorro('Mitzie'); +cachorro.falar(); // Mitzie lati.</pre> + +<p>Note que classes não extendem objetos normais (não construíveis). Se você quer herdar de um objeto, é necessário utilizar {{jsxref("Object.setPrototypeOf()")}}:</p> + +<pre class="brush: js"><code>let Animal = { + falar() { + console.log(this.nome + ' faça barulho.'); + } +}; + +class Cachorro { + constructor(nome) { + this.nome = nome; +</code> } +} + +Object.setPrototypeOf(Cachorro.prototype, Animal); + +let cachorro = new Cachorro('Mitzie'); +cachorro.falar(); //Mitzie faça barulho.</pre> + +<h2 id="Species">Species</h2> + +<p>Você pode querer retornar um objeto {{jsxref("Array")}} na sua classe <code>MinhaArray</code> derivada de array. O padrão Species permite a sobrescrita do construtor padrão.</p> + +<p>Por exemplo, quando utilizando um método como {{jsxref("Array.map", "map()")}} que retorna o construtor padrão, você pode querer que esse método retorne um objeto <code>Array</code> ao invés do objeto <code>MinhaArray</code>. O {{jsxref("Symbol.species")}} te permite fazer isso:</p> + +<pre class="brush: js">class MinhaArray extends Array { + // Sobrescreve species para o construtor da classe pai Array + static get [Symbol.species]() { return Array; } +} + +let a = new MinhaArray(1,2,3); +let mapped = a.map(x => x * x); + +console.log(mapped instanceof MyArray); // false +console.log(mapped instanceof Array); // true +</pre> + +<h2 id="Chamada_da_classe_pai_com_super">Chamada da classe pai com <code>super</code></h2> + +<p>A palavra-chave (keyword) <code>super</code> é utilizada para chamar funções que pertencem ao pai do objeto.</p> + +<pre class="brush: js">class Gato { + constructor(nome) { + this.nome = nome; + } + + falar() { + console.log(this.nome + ' faça barulho.'); + } +} + +class Leao extends Gato { + falar() { + super.falar(); + console.log(this.nome + ' roars.'); + } +} + +let leao = new Leao('Fuzzy'); +leao.falar(); + +// Fuzzy faça barulho. +// Fuzzy roars. + +</pre> + +<h2 id="Mix-ins">Mix-ins</h2> + +<p>Subclasses abstratas ou <em>mix-ins</em> são templates para classes. Uma classe do ECMAScript pode apenas ter uma classe pai, assim sendo, não é possível a classe ter herança múltipla.</p> + +<p>Para se ter um comportamento similar ao de herança múltipla no ECMAScript usa-se mix-ins, uma forma de implementar mix-ins é usar um template de subclasse que é uma função que instancia uma classe base e retorna uma subclasse extendida desta classe base:</p> + +<pre class="brush: js">class Humano { + constructor(nome) { + this.nome = nome; + } + andar() { + return this.nome+' andou um passo' + } +} + +const HumanoFalante = Base => class extends Base { + falar() { + return this.nome+' diz: olá mundo!' + } +} + +const HumanoFalanteMixado = Base => class extends Base {} + +const HumanoFinal = HumanoFalanteMixado(HumanoFalante(Humano)) + +const humano = new HumanoFinal('Bill Gates') + +console.log(humano.andar()) +console.log(humano.falar()) +</pre> + +<h2 id="Especificações">Especificações</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Especificação</th> + <th scope="col">Status</th> + <th scope="col">Comentário</th> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-class-definitions', 'Class definitions')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>Definição inicial.</td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilidade_de_navegadores">Compatibilidade de navegadores</h2> + + + +<p>{{Compat("javascript.classes")}}</p> + +<h2 id="Rodando_com_Scratchpad">Rodando com Scratchpad</h2> + +<p>Uma classe não pode ser redefinida. Se você estiver rodando código com Scratchpad (Menu do Firefox Ferramentas > Web Developer > Scratchpad) e você acionar 'Run' a uma definição de uma classe com o mesmo nome duas vezes, você verá um confuso SyntaxError: redeclaration of let <class-name> (Erro de Sintaxe: redeclaração de let <nome-da-classe>).</p> + +<p>Para reacionar (re-run) uma definição, use o menu do Scratchpad em Execute > Reload and Run (Executar > Atualizar e Rodar).<br> + Por favor, vote no bug <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1428672">#1428672</a>.</p> + +<h2 id="Veja_também">Veja também</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions">Funções</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/class">Declaração de <code>classes</code> (class declaration</a>)</li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Operators/class">Expressão de <code>classes</code> (class expression</a>)</li> + <li>{{jsxref("Operators/super", "super")}}</li> + <li><a href="https://hacks.mozilla.org/2015/07/es6-in-depth-classes/">Blog post: "ES6 In Depth: Classes"</a></li> +</ul> |