Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
First, let's see why the latter code doesn't work.
Primeiro, vamos ver por que o segundo código não funciona.

The reason becomes obvious if we try to run it. An inheriting class constructor must call `super()`. Otherwise `"this"` won't be "defined".
O motivo fica óbvio se tentarmos rodá-lo. O construtor de uma classe que herda precisa chamar `super()`. Caso contrário, o `"this"` não será "definido".

So here's the fix:
Então aqui está a correção:

```js run
class Rabbit extends Object {
constructor(name) {
*!*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"construtor do pai" soa estranho e pode ser ambíguo. O termo comum em português é "construtor da classe pai".

Suggested change
*!*
super(); // precisamos chamar o construtor da classe pai ao herdar

super(); // need to call the parent constructor when inheriting
super(); // precisamos chamar o construtor da classe pai ao herdar
*/!*
this.name = name;
}
Expand All @@ -19,16 +19,16 @@ let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // true
```

But that's not all yet.
Mas isso ainda não é tudo.

Even after the fix, there's still an important difference between `"class Rabbit extends Object"` and `class Rabbit`.
Mesmo depois da correção, ainda existe uma diferença importante entre `"class Rabbit extends Object"` e `class Rabbit`.

As we know, the "extends" syntax sets up two prototypes:
Como sabemos, a sintaxe "extends" configura dois protótipos:

1. Between `"prototype"` of the constructor functions (for methods).
2. Between the constructor functions themselves (for static methods).
1. Entre o `"prototype"` das funções construtoras (para métodos).
2. Entre as próprias funções construtoras (para métodos estáticos).

In the case of `class Rabbit extends Object` it means:
No caso de `class Rabbit extends Object`, isso significa:

```js run
class Rabbit extends Object {}
Expand All @@ -37,45 +37,45 @@ alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true
```

So `Rabbit` now provides access to the static methods of `Object` via `Rabbit`, like this:
Então `Rabbit` agora fornece acesso aos métodos estáticos de `Object` através de `Rabbit`, assim:

```js run
class Rabbit extends Object {}

*!*
// normally we call Object.getOwnPropertyNames
// normalmente chamamos Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
*/!*
```

But if we don't have `extends Object`, then `Rabbit.__proto__` is not set to `Object`.
Mas se não tivermos `extends Object`, então `Rabbit.__proto__` não é definido como `Object`.

Here's the demo:
Aqui está a demonstração:

```js run
class Rabbit {}

alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // as any function by default
alert( Rabbit.__proto__ === Function.prototype ); // como qualquer função por padrão

*!*
// error, no such function in Rabbit
// erro, não existe essa função em Rabbit
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
*/!*
```

So `Rabbit` doesn't provide access to static methods of `Object` in that case.
Então, nesse caso, `Rabbit` não fornece acesso aos métodos estáticos de `Object`.

By the way, `Function.prototype` also has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`.
Aliás, `Function.prototype` também tem métodos "genéricos" de função, como `call`, `bind`, etc. Eles acabam disponíveis em ambos os casos, porque, para o construtor nativo `Object`, `Object.__proto__ === Function.prototype`.

Here's the picture:
Aqui está a imagem:

![](rabbit-extends-object.svg)

So, to put it short, there are two differences:
Então, resumindo, existem duas diferenças:

| class Rabbit | class Rabbit extends Object |
|--------------|------------------------------|
| -- | needs to call `super()` in constructor |
| -- | precisa chamar `super()` no construtor |
| `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` |
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 3

---

# Class extends Object?
# Classe estende Object?

As we know, all objects normally inherit from `Object.prototype` and get access to "generic" object methods like `hasOwnProperty` etc.
Como sabemos, todos os objetos normalmente herdam de `Object.prototype` e têm acesso aos métodos "genéricos" de objeto, como `hasOwnProperty`, etc.

For instance:
Por exemplo:

```js run
class Rabbit {
Expand All @@ -18,16 +18,16 @@ class Rabbit {
let rabbit = new Rabbit("Rab");

*!*
// hasOwnProperty method is from Object.prototype
// o método hasOwnProperty vem de Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true
*/!*
```

But if we spell it out explicitly like `"class Rabbit extends Object"`, then the result would be different from a simple `"class Rabbit"`?
Mas se escrevermos isso explicitamente como `"class Rabbit extends Object"`, o resultado seria diferente de um simples `"class Rabbit"`?

What's the difference?
Qual é a diferença?

Here's an example of such code (it doesn't work -- why? fix it?):
Aqui está um exemplo desse código (ele não funciona -- por quê? corrija-o?):

```js
class Rabbit extends Object {
Expand Down
104 changes: 52 additions & 52 deletions 1-js/09-classes/03-static-properties-methods/article.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

# Static properties and methods
# Propriedades e métodos estáticos

We can also assign a method to the class as a whole. Such methods are called *static*.
Também podemos atribuir um método à classe como um todo. Esses métodos são chamados de *estáticos*.

In a class declaration, they are prepended by `static` keyword, like this:
Em uma declaração de classe, eles são precedidos pela palavra-chave `static`, assim:

```js run
class User {
Expand All @@ -17,7 +17,7 @@ class User {
User.staticMethod(); // true
```

That actually does the same as assigning it as a property directly:
Isso, na verdade, faz a mesma coisa que atribuí-lo diretamente como uma propriedade:

```js run
class User { }
Expand All @@ -29,13 +29,13 @@ User.staticMethod = function() {
User.staticMethod(); // true
```

The value of `this` in `User.staticMethod()` call is the class constructor `User` itself (the "object before dot" rule).
O valor de `this` na chamada `User.staticMethod()` é o próprio construtor da classe `User` (a regra do "objeto antes do ponto").

Usually, static methods are used to implement functions that belong to the class as a whole, but not to any particular object of it.
Geralmente, métodos estáticos são usados para implementar funções que pertencem à classe como um todo, mas não a nenhum objeto específico dela.

For instance, we have `Article` objects and need a function to compare them.
Por exemplo, temos objetos `Article` e precisamos de uma função para compará-los.

A natural solution would be to add `Article.compare` static method:
Uma solução natural seria adicionar o método estático `Article.compare`:

```js run
class Article {
Expand All @@ -51,7 +51,7 @@ class Article {
*/!*
}

// usage
// uso
let articles = [
new Article("HTML", new Date(2019, 1, 1)),
new Article("CSS", new Date(2019, 0, 1)),
Expand All @@ -65,19 +65,19 @@ articles.sort(Article.compare);
alert( articles[0].title ); // CSS
```

Here `Article.compare` method stands "above" articles, as a means to compare them. It's not a method of an article, but rather of the whole class.
Aqui o método `Article.compare` fica "acima" dos artigos, como um meio de compará-los. Não é um método de um artigo, mas sim de toda a classe.

Another example would be a so-called "factory" method.
Outro exemplo seria um método chamado de "fábrica".

Let's say, we need multiple ways to create an article:
Digamos que precisamos de várias formas de criar um artigo:

1. Create by given parameters (`title`, `date` etc).
2. Create an empty article with today's date.
3. ...or else somehow.
1. Criar a partir de parâmetros fornecidos (`title`, `date`, etc).
2. Criar um artigo vazio com a data de hoje.
3. ...ou de alguma outra forma.

The first way can be implemented by the constructor. And for the second one we can make a static method of the class.
A primeira forma pode ser implementada pelo construtor. E para a segunda, podemos fazer um método estático da classe.

Such as `Article.createTodays()` here:
Como o `Article.createTodays()` aqui:

```js run
class Article {
Expand All @@ -88,43 +88,43 @@ class Article {

*!*
static createTodays() {
// remember, this = Article
return new this("Today's digest", new Date());
// lembre-se, this = Article
return new this("Resumo de hoje", new Date());
}
*/!*
}

let article = Article.createTodays();

alert( article.title ); // Today's digest
alert( article.title ); // Resumo de hoje
```

Now every time we need to create a today's digest, we can call `Article.createTodays()`. Once again, that's not a method of an article, but a method of the whole class.
Agora, toda vez que precisarmos criar um resumo de hoje, podemos chamar `Article.createTodays()`. Mais uma vez, isso não é um método de um artigo, mas um método de toda a classe.

Static methods are also used in database-related classes to search/save/remove entries from the database, like this:
Métodos estáticos também são usados em classes relacionadas a banco de dados, para buscar/salvar/remover registros do banco, assim:

```js
// assuming Article is a special class for managing articles
// static method to remove the article by id:
// supondo que Article seja uma classe especial para gerenciar artigos
// método estático para remover o artigo pelo id:
Article.remove({id: 12345});
```

````warn header="Static methods aren't available for individual objects"
Static methods are callable on classes, not on individual objects.
````warn header="Métodos estáticos não estão disponíveis para objetos individuais"
Métodos estáticos podem ser chamados em classes, não em objetos individuais.

E.g. such code won't work:
Por exemplo, um código assim não vai funcionar:

```js
// ...
article.createTodays(); /// Error: article.createTodays is not a function
```
````

## Static properties
## Propriedades estáticas

[recent browser=Chrome]

Static properties are also possible, they look like regular class properties, but prepended by `static`:
Propriedades estáticas também são possíveis. Elas se parecem com propriedades comuns de classe, mas são precedidas por `static`:

```js run
class Article {
Expand All @@ -134,17 +134,17 @@ class Article {
alert( Article.publisher ); // Ilya Kantor
```

That is the same as a direct assignment to `Article`:
Isso é o mesmo que uma atribuição direta a `Article`:

```js
Article.publisher = "Ilya Kantor";
```

## Inheritance of static properties and methods [#statics-and-inheritance]
## Herança de propriedades e métodos estáticos [#statics-and-inheritance]

Static properties and methods are inherited.
Propriedades e métodos estáticos são herdados.

For instance, `Animal.compare` and `Animal.planet` in the code below are inherited and accessible as `Rabbit.compare` and `Rabbit.planet`:
Por exemplo, `Animal.compare` e `Animal.planet` no código abaixo são herdados e acessíveis como `Rabbit.compare` e `Rabbit.planet`:

```js run
class Animal {
Expand All @@ -168,7 +168,7 @@ class Animal {

}

// Inherit from Animal
// Herda de Animal
class Rabbit extends Animal {
hide() {
alert(`${this.name} hides!`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As strings dos alertas neste exemplo (hides! aqui, runs with speed na linha 160, "Earth" na linha 151) e os comentários de saída (// Black Rabbit runs with speed 5. na linha 187, // Earth na linha 189) continuam em inglês, enquanto os comentários ao redor foram traduzidos. Quem executar o exemplo vai ver os alertas em inglês. Vale traduzir (por exemplo ${this.name} se esconde!, ${this.name} corre com velocidade ${this.speed}., "Terra") e atualizar os comentários de saída do mesmo jeito. Se a ideia for manter igual ao capítulo 02-class-inheritance, que ainda não foi traduzido, dá para ignorar.

Expand All @@ -189,43 +189,43 @@ rabbits[0].run(); // Black Rabbit runs with speed 5.
alert(Rabbit.planet); // Earth
```

Now when we call `Rabbit.compare`, the inherited `Animal.compare` will be called.
Agora, quando chamamos `Rabbit.compare`, o `Animal.compare` herdado será chamado.

How does it work? Again, using prototypes. As you might have already guessed, `extends` gives `Rabbit` the `[[Prototype]]` reference to `Animal`.
Como isso funciona? De novo, usando protótipos. Como você já deve ter imaginado, o `extends` dá a `Rabbit` a referência `[[Prototype]]` para `Animal`.

![](animal-rabbit-static.svg)

So, `Rabbit extends Animal` creates two `[[Prototype]]` references:
Então, `Rabbit extends Animal` cria duas referências `[[Prototype]]`:

1. `Rabbit` function prototypally inherits from `Animal` function.
2. `Rabbit.prototype` prototypally inherits from `Animal.prototype`.
1. A função `Rabbit` herda prototipicamente da função `Animal`.
2. `Rabbit.prototype` herda prototipicamente de `Animal.prototype`.

As a result, inheritance works both for regular and static methods.
Como resultado, a herança funciona tanto para métodos comuns quanto para métodos estáticos.

Here, let's check that by code:
Aqui, vamos conferir isso pelo código:

```js run
class Animal {}
class Rabbit extends Animal {}

// for statics
// para estáticos
alert(Rabbit.__proto__ === Animal); // true

// for regular methods
// para métodos comuns
alert(Rabbit.prototype.__proto__ === Animal.prototype); // true
```

## Summary
## Resumo

Static methods are used for the functionality that belongs to the class "as a whole". It doesn't relate to a concrete class instance.
Métodos estáticos são usados para funcionalidades que pertencem à classe "como um todo". Não se relacionam a uma instância concreta da classe.

For example, a method for comparison `Article.compare(article1, article2)` or a factory method `Article.createTodays()`.
Por exemplo, um método de comparação `Article.compare(article1, article2)` ou um método de fábrica `Article.createTodays()`.

They are labeled by the word `static` in class declaration.
Eles são identificados pela palavra-chave `static` na declaração da classe.

Static properties are used when we'd like to store class-level data, also not bound to an instance.
Propriedades estáticas são usadas quando queremos guardar dados no nível da classe, também não vinculados a uma instância.

The syntax is:
A sintaxe é:

```js
class MyClass {
Expand All @@ -237,13 +237,13 @@ class MyClass {
}
```

Technically, static declaration is the same as assigning to the class itself:
Tecnicamente, uma declaração estática é o mesmo que atribuir diretamente à própria classe:

```js
MyClass.property = ...
MyClass.method = ...
```

Static properties and methods are inherited.
Propriedades e métodos estáticos são herdados.

For `class B extends A` the prototype of the class `B` itself points to `A`: `B.[[Prototype]] = A`. So if a field is not found in `B`, the search continues in `A`.
Para `class B extends A`, o próprio protótipo da classe `B` aponta para `A`: `B.[[Prototype]] = A`. Então, se um campo não é encontrado em `B`, a busca continua em `A`.