1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
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="/pt-BR/docs/Web/JavaScript/Reference/Operators/function">"function expressions"</a> e <a href="/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="Browser_compatibility">Compatibilidade com 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>
|