Skip to content

Object methods, "this" #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
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
26 changes: 10 additions & 16 deletions 1-js/04-object-basics/04-object-methods/2-check-syntax/solution.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,37 @@
**Error**!
**Erro**!

Try it:
Tente isto:

```js run
let user = {
name: "John",
go: function() { alert(this.name) }
}

(user.go)() // error!
(user.go)() // erro!
```

The error message in most browsers does not give understanding what went wrong.
A mensagem de erro, na maior parte dos navegadores (*browsers*), não nos dá uma compreensão do que ocorre de errado.

**The error appears because a semicolon is missing after `user = {...}`.**
**O erro aparece porque falta um ponto-e-vírgula depois de `user = {...}`.**

JavaScript does not assume a semicolon before a bracket `(user.go)()`, so it reads the code like:
JavaScript não assume um ponto-e-vírgula antes do parêntese de `(user.go)()`, por isso lê o código como:

```js no-beautify
let user = { go:... }(user.go)()
```

Then we can also see that such a joint expression is syntactically a call of the object `{ go: ... }` as a function with the argument `(user.go)`. And that also happens on the same line with `let user`, so the `user` object has not yet even been defined, hence the error.
Assim, podemos também observar que, tal expressão conjunta é sintáticamente uma chamada do objeto `{ go: ... }` como uma função, tomando `(user.go)` como argumento. E, isso também ocorre na mesma linha que `let user`, então o objeto `user` ainda não foi definido, e por isto o erro.

If we insert the semicolon, all is fine:
Se inserirmos o ponto-e-vírgula, tudo estará bem:

```js run
let user = {
name: "John",
go: function() { alert(this.name) }
}*!*;*/!*

(user.go)() // John
(user.go)() // 'John'
```

Please note that brackets around `(user.go)` do nothing here. Usually they setup the order of operations, but here the dot `.` works first anyway, so there's no effect. Only the semicolon thing matters.






Por favor, note que os parênteses em `(user.go)` nada aqui fazem. Geralmente, eles estabelecem a ordem das operações, mas aqui o ponto `.` já funciona à partida, então não têm efeito algum. Apenas, aquele ponto-e-vírgula importa.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
importance: 2
importância: 2

---

# Syntax check
# Verificação sintática

What is the result of this code?
Qual o resultado deste código?


```js no-beautify
Expand All @@ -16,4 +16,4 @@ let user = {
(user.go)()
```

P.S. There's a pitfall :)
P.S. Existe um falha :)
21 changes: 10 additions & 11 deletions 1-js/04-object-basics/04-object-methods/3-why-this/solution.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@

Here's the explanations.
Aqui estão as explicações.

1. That's a regular object method call.
1. É uma regular invocação do método do objeto.

2. The same, brackets do not change the order of operations here, the dot is first anyway.
2. O mesmo. Aqui, os parênteses não alteram a ordem das operações, o ponto já funciona à primeira.

3. Here we have a more complex call `(expression).method()`. The call works as if it were split into two lines:
3. Aqui, temos uma chamada `(expression).method()` mais complexa. A chamada funciona como se fosse particionada em duas linhas:

```js no-beautify
f = obj.go; // calculate the expression
f(); // call what we have
f = obj.go; // calcula a expressão
f(); // invoca o resultado
```

Here `f()` is executed as a function, without `this`.
Aqui, `f()` é executada como uma função, sem `this`.

4. The similar thing as `(3)`, to the left of the dot `.` we have an expression.
4. Algo similar a `(3)`, à esquerda do ponto `.` temos uma expressão.

To explain the behavior of `(3)` and `(4)` we need to recall that property accessors (dot or square brackets) return a value of the Reference Type.

Any operation on it except a method call (like assignment `=` or `||`) turns it into an ordinary value, which does not carry the information allowing to set `this`.
Para explicar o comportamento de `(3)` e `(4)`, recordemo-nos que propriedades acessoras (o ponto ou os parênteses retos) retornam um valor do Tipo *Reference*.

Qualquer operação com elas (como, atribuição `=` ou `||`), exceto a chamada a um método, o transforma num valor ordinário, o qual não transporta a informação necessária para configurar `this`.
9 changes: 4 additions & 5 deletions 1-js/04-object-basics/04-object-methods/3-why-this/task.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
importance: 3
importância: 3

---

# Explain the value of "this"
# Explique o valor de "this"

In the code below we intend to call `user.go()` method 4 times in a row.
No código abaixo, pretendemos invocar o método `user.go()` 4 vezes seguidas.

But calls `(1)` and `(2)` works differently from `(3)` and `(4)`. Why?
Mas, as chamadas `(1)` e `(2)` funcionam de forma diferente do que as `(3)` e `(4)`. Porquê?

```js run no-beautify
let obj, method;
Expand All @@ -23,4 +23,3 @@ obj.go(); // (1) [object Object]

(obj.go || obj.stop)(); // (4) undefined
```

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
**Answer: an error.**
**Resposta: um erro.**

Try it:
Tente isto:
```js run
function makeUser() {
return {
Expand All @@ -12,17 +12,18 @@ function makeUser() {
let user = makeUser();

alert( user.ref.name ); // Error: Cannot read property 'name' of undefined
// (Erro: não é possível ler a propriedade 'name' de undefined)
```

That's because rules that set `this` do not look at object literals.
Isto, porque regras que estabelecem `this` não têm em conta objetos literais.

Here the value of `this` inside `makeUser()` is `undefined`, because it is called as a function, not as a method.
Aqui, o valor de `this` dentro de `makeUser()` está `undefined`, porque é invocado como uma função, não como um método.

And the object literal itself has no effect on `this`. The value of `this` is one for the whole function, code blocks and object literals do not affect it.
E um objeto literal não possui qualquer efeito sobre `this`. O valor de `this` é o mesmo para toda uma função, e tanto blocos de código como objetos literais não exercem qualquer influência sobre ele.

So `ref: this` actually takes current `this` of the function.
Assim, na realidade `ref: this` recebe o valor atual `this` da função.

Here's the opposite case:
Aqui, o caso oposto:

```js run
function makeUser() {
Expand All @@ -38,9 +39,9 @@ function makeUser() {

let user = makeUser();

alert( user.ref().name ); // John
alert( user.ref().name ); // 'John'
```

Now it works, because `user.ref()` is a method. And the value of `this` is set to the object before dot `.`.
Agora funciona, porque `user.ref()` é um método. E, o valor de `this` já é uma referência ao objeto antes do ponto `.`.


Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
importance: 5
importância: 5

---

# Using "this" in object literal
# Usando "this" num objeto literal

Here the function `makeUser` returns an object.
Aqui, a função `makeUser` retorna um objeto.

What is the result of accessing its `ref`? Why?
Qual o resultado de aceder à sua `ref`? Porquê?

```js
function makeUser() {
Expand All @@ -18,6 +18,5 @@ function makeUser() {

let user = makeUser();

alert( user.ref.name ); // What's the result?
alert( user.ref.name ); // Qual o resultado?
```

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

describe("calculator", function() {

context("when 2 and 3 entered", function() {
context("quando são entrados 2 e 3", function() {
beforeEach(function() {
sinon.stub(window, "prompt");

Expand All @@ -16,11 +16,11 @@ describe("calculator", function() {
prompt.restore();
});

it("the sum is 5", function() {
it("a soma é 5", function() {
assert.equal(calculator.sum(), 5);
});

it("the multiplication product is 6", function() {
it("o produto da multiplicação é 6", function() {
assert.equal(calculator.mul(), 6);
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

```js run demo solution
```js execute a solução demo
let calculator = {
sum() {
return this.a + this.b;
Expand Down
15 changes: 7 additions & 8 deletions 1-js/04-object-basics/04-object-methods/7-calculator/task.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
importance: 5
importância: 5

---

# Create a calculator
# Crie uma calculadora

Create an object `calculator` with three methods:
Crie um objeto `calculator` com três métodos:

- `read()` prompts for two values and saves them as object properties.
- `sum()` returns the sum of saved values.
- `mul()` multiplies saved values and returns the result.
- `read()` pergunta (*prompts*) por dois valores e os guarda (*saves*) como propriedades de um objeto.
- `sum()` retorna a soma dos valores guardados.
- `mul()` multiplica os valores guardados e retorna o resultado.

```js
let calculator = {
// ... your code ...
// ... o seu código ...
};

calculator.read();
Expand All @@ -21,4 +21,3 @@ alert( calculator.mul() );
```

[demo]

Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,24 @@ describe('Ladder', function() {
ladder.step = 0;
});

it('up() should return this', function() {
it('up() deveria retornar this', function() {
assert.equal(ladder.up(), ladder);
});

it('down() should return this', function() {
it('down() deveria retornar this', function() {
assert.equal(ladder.down(), ladder);
});

it('showStep() should call alert', function() {
it('showStep() deveria chamar alert', function() {
ladder.showStep();
assert(alert.called);
});

it('up() should increase step', function() {
it('up() deveria incrementar step', function() {
assert.equal(ladder.up().up().step, 2);
});

it('down() should decrease step', function() {
it('down() deveria decrementar step', function() {
assert.equal(ladder.down().step, -1);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The solution is to return the object itself from every call.
A solução será retornar o próprio objeto em cada chamada.

```js run demo
```js execute demo
let ladder = {
step: 0,
up() {
Expand All @@ -26,7 +26,7 @@ let ladder = {
ladder.up().up().down().up().down().showStep(); // 1
```

We also can write a single call per line. For long chains it's more readable:
Podemos também escrever uma única chamada por linha. Para longas cadeias é mais legível:

```js
ladder
Expand Down
14 changes: 7 additions & 7 deletions 1-js/04-object-basics/04-object-methods/8-chain-calls/task.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
importance: 2
importância: 2

---

# Chaining
# Encadeamento

There's a `ladder` object that allows to go up and down:
Existe um objeto `ladder` (escada) que permite subir e descer:

```js
let ladder = {
Expand All @@ -15,13 +15,13 @@ let ladder = {
down() {
this.step--;
},
showStep: function() { // shows the current step
showStep: function() { // mostra o atual degrau
alert( this.step );
}
};
```

Now, if we need to make several calls in sequence, can do it like this:
Agora, se precisarmos de fazer várias chamadas em sequência, podemos fazê-las desta forma:

```js
ladder.up();
Expand All @@ -30,10 +30,10 @@ ladder.down();
ladder.showStep(); // 1
```

Modify the code of `up`, `down` and `showStep` to make the calls chainable, like this:
Modifique o código de `up`, `down` e `showStep` para tornar as chamadas encadeáveis, como:

```js
ladder.up().up().down().showStep(); // 1
```

Such approach is widely used across JavaScript libraries.
Tal abordagem é amplamente utilizada em bibliotecas (*libraries*) de JavaScript.
Loading