Skip to content
Open
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,5 +1,5 @@
The answer is: **Pete**.
A resposta é: **Pete**.

A function gets outer variables as they are now, it uses the most recent values.
Uma função recebe as variáveis externas como elas estão agora, ela usa os valores mais recentes.

Old variable values are not saved anywhere. When a function wants a variable, it takes the current value from its own Lexical Environment or the outer one.
Valores antigos de variáveis não são salvos em lugar nenhum. Quando uma função quer uma variável, ela pega o valor atual do seu próprio Ambiente Léxico ou do externo.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ importance: 5

---

# Does a function pickup latest changes?
# Uma função pega as mudanças mais recentes?

The function sayHi uses an external variable name. When the function runs, which value is it going to use?
A função sayHi usa uma variável externa name. Quando a função roda, qual valor ela vai usar?

```js
let name = "John";
Expand All @@ -15,9 +15,9 @@ function sayHi() {

name = "Pete";

sayHi(); // what will it show: "John" or "Pete"?
sayHi(); // o que vai mostrar: "John" ou "Pete"?
```

Such situations are common both in browser and server-side development. A function may be scheduled to execute later than it is created, for instance after a user action or a network request.
Situações assim são comuns tanto no desenvolvimento para navegador quanto no lado do servidor. Uma função pode ser agendada para executar depois de ser criada, por exemplo, após uma ação do usuário ou uma requisição de rede.

So, the question is: does it pick up the latest changes?
Então, a pergunta é: ela pega as mudanças mais recentes?
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ function makeArmy() {
let shooters = [];

for(let i = 0; i < 10; i++) {
let shooter = function() { // shooter function
alert( i ); // should show its number
let shooter = function() { // função shooter
alert( i ); // deveria mostrar seu número
};
shooters.push(shooter);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ function makeArmy() {

let i = 0;
while (i < 10) {
let shooter = function() { // shooter function
alert( i ); // should show its number
let shooter = function() { // função shooter
alert( i ); // deveria mostrar seu número
};
shooters.push(shooter);
i++;
Expand All @@ -16,7 +16,7 @@ function makeArmy() {
/*
let army = makeArmy();

army[0](); // the shooter number 0 shows 10
army[5](); // and number 5 also outputs 10...
// ... all shooters show 10 instead of their 0, 1, 2, 3...
army[0](); // o shooter número 0 mostra 10
army[5](); // e o número 5 também exibe 10...
// ... todos os shooters mostram 10 em vez de 0, 1, 2, 3...
*/
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
describe("army", function() {

let army;

before(function() {
army = makeArmy();
window.alert = sinon.stub(window, "alert");
});

it("army[0] shows 0", function() {
it("army[0] mostra 0", function() {
army[0]();
assert(alert.calledWith(0));
});


it("army[5] shows 5", function() {
it("army[5] mostra 5", function() {
army[5]();
assert(alert.calledWith(5));
});
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 28 additions & 28 deletions 1-js/06-advanced-functions/03-closure/10-make-army/solution.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@

Let's examine what exactly happens inside `makeArmy`, and the solution will become obvious.
Vamos examinar o que exatamente acontece dentro de `makeArmy`, e a solução vai ficar óbvia.

1. It creates an empty array `shooters`:
1. Ele cria um array vazio `shooters`:

```js
let shooters = [];
```
2. Fills it with functions via `shooters.push(function)` in the loop.
2. Preenche ele com funções via `shooters.push(function)` no laço.

Every element is a function, so the resulting array looks like this:
Cada elemento é uma função, então o array resultante fica assim:

```js no-beautify
shooters = [
Expand All @@ -25,40 +25,40 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
];
```

3. The array is returned from the function.
3. O array é retornado pela função.

Then, later, the call to any member, e.g. `army[5]()` will get the element `army[5]` from the array (which is a function) and calls it.
Então, mais tarde, a chamada a qualquer membro, ex.: `army[5]()`, vai pegar o elemento `army[5]` do array (que é uma função) e chamá-lo.

Now why do all such functions show the same value, `10`?
Agora, por que todas essas funções mostram o mesmo valor, `10`?

That's because there's no local variable `i` inside `shooter` functions. When such a function is called, it takes `i` from its outer lexical environment.
Isso acontece porque não existe uma variável local `i` dentro das funções `shooter`. Quando uma dessas funções é chamada, ela pega `i` do seu ambiente léxico externo.

Then, what will be the value of `i`?
Então, qual vai ser o valor de `i`?

If we look at the source:
Se olharmos o código-fonte:

```js
function makeArmy() {
...
let i = 0;
while (i < 10) {
let shooter = function() { // shooter function
alert( i ); // should show its number
let shooter = function() { // função shooter
alert( i ); // deveria mostrar seu número
};
shooters.push(shooter); // add function to the array
shooters.push(shooter); // adiciona a função ao array
i++;
}
...
}
```

We can see that all `shooter` functions are created in the lexical environment of `makeArmy()` function. But when `army[5]()` is called, `makeArmy` has already finished its job, and the final value of `i` is `10` (`while` stops at `i=10`).
Podemos ver que todas as funções `shooter` são criadas no ambiente léxico da função `makeArmy()`. Mas quando `army[5]()` é chamada, `makeArmy` já terminou seu trabalho, e o valor final de `i` é `10` (`while` para em `i=10`).

As the result, all `shooter` functions get the same value from the outer lexical environment and that is, the last value, `i=10`.
Como resultado, todas as funções `shooter` pegam o mesmo valor do ambiente léxico externo, que é o último valor, `i=10`.

![](lexenv-makearmy-empty.svg)

As you can see above, on each iteration of a `while {...}` block, a new lexical environment is created. So, to fix this, we can copy the value of `i` into a variable within the `while {...}` block, like this:
Como você pode ver acima, em cada iteração de um bloco `while {...}`, um novo ambiente léxico é criado. Então, para corrigir isso, podemos copiar o valor de `i` para uma variável dentro do bloco `while {...}`, assim:

```js run
function makeArmy() {
Expand All @@ -69,8 +69,8 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
*!*
let j = i;
*/!*
let shooter = function() { // shooter function
alert( *!*j*/!* ); // should show its number
let shooter = function() { // função shooter
alert( *!*j*/!* ); // deveria mostrar seu número
};
shooters.push(shooter);
i++;
Expand All @@ -81,18 +81,18 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco

let army = makeArmy();

// Now the code works correctly
// Agora o código funciona corretamente
army[0](); // 0
army[5](); // 5
```

Here `let j = i` declares an "iteration-local" variable `j` and copies `i` into it. Primitives are copied "by value", so we actually get an independent copy of `i`, belonging to the current loop iteration.
Aqui, `let j = i` declara uma variável "local à iteração", `j`, e copia `i` para ela. Primitivos são copiados "por valor", então na verdade obtemos uma cópia independente de `i`, pertencente à iteração atual do laço.

The shooters work correctly, because the value of `i` now lives a little bit closer. Not in `makeArmy()` Lexical Environment, but in the Lexical Environment that corresponds to the current loop iteration:
Os shooters funcionam corretamente, porque o valor de `i` agora vive um pouco mais perto. Não no Ambiente Léxico de `makeArmy()`, mas no Ambiente Léxico que corresponde à iteração atual do laço:

![](lexenv-makearmy-while-fixed.svg)

Such a problem could also be avoided if we used `for` in the beginning, like this:
Esse problema também poderia ser evitado se usássemos `for` desde o início, assim:

```js run demo
function makeArmy() {
Expand All @@ -102,8 +102,8 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
*!*
for(let i = 0; i < 10; i++) {
*/!*
let shooter = function() { // shooter function
alert( i ); // should show its number
let shooter = function() { // função shooter
alert( i ); // deveria mostrar seu número
};
shooters.push(shooter);
}
Expand All @@ -117,13 +117,13 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco
army[5](); // 5
```

That's essentially the same, because `for` on each iteration generates a new lexical environment, with its own variable `i`. So `shooter` generated in every iteration references its own `i`, from that very iteration.
Isso é essencialmente a mesma coisa, porque o `for`, em cada iteração, gera um novo ambiente léxico, com sua própria variável `i`. Então o `shooter` gerado em cada iteração referencia seu próprio `i`, daquela mesma iteração.

![](lexenv-makearmy-for-fixed.svg)

Now, as you've put so much effort into reading this, and the final recipe is so simple - just use `for`, you may wonder -- was it worth that?
Agora, já que você se esforçou tanto pra ler isso tudo, e a receita final é tão simples -- só usar `for` -- você deve estar se perguntando -- valeu a pena?

Well, if you could easily answer the question, you wouldn't read the solution. So, hopefully this task must have helped you to understand things a bit better.
Bom, se você conseguisse responder a pergunta facilmente, não leria a solução. Então, esperamos que essa tarefa tenha ajudado você a entender as coisas um pouco melhor.

Besides, there are indeed cases when one prefers `while` to `for`, and other scenarios, where such problems are real.
Além disso, existem sim casos em que se prefere `while` a `for`, e outros cenários, onde esses problemas são reais.

26 changes: 13 additions & 13 deletions 1-js/06-advanced-functions/03-closure/10-make-army/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,40 @@ importance: 5

---

# Army of functions
# Exército de funções

The following code creates an array of `shooters`.
O código a seguir cria um array de `shooters`.

Every function is meant to output its number. But something is wrong...
Cada função deveria exibir seu número. Mas algo está errado...

```js run
function makeArmy() {
let shooters = [];

let i = 0;
while (i < 10) {
let shooter = function() { // create a shooter function,
alert( i ); // that should show its number
let shooter = function() { // cria uma função shooter,
alert( i ); // que deveria mostrar seu número
};
shooters.push(shooter); // and add it to the array
shooters.push(shooter); // e a adiciona ao array
i++;
}

// ...and return the array of shooters
// ...e retorna o array de shooters
return shooters;
}

let army = makeArmy();

*!*
// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.
// todos os shooters mostram 10 em vez de seus números 0, 1, 2, 3...
army[0](); // 10 do shooter número 0
army[1](); // 10 do shooter número 1
army[2](); // 10 ...e assim por diante.
*/!*
```

Why do all of the shooters show the same value?
Por que todos os shooters mostram o mesmo valor?

Fix the code so that they work as intended.
Corrija o código para que eles funcionem como pretendido.

Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
The answer is: **Pete**.
A resposta é: **Pete**.

The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference:
A função `work()` no código abaixo pega `name` do seu lugar de origem, através da referência do ambiente léxico externo:

![](lexenv-nested-work.svg)

So, the result is `"Pete"` here.
Então, o resultado aqui é `"Pete"`.

But if there were no `let name` in `makeWorker()`, then the search would go outside and take the global variable as we can see from the chain above. In that case the result would be `"John"`.
Mas se não houvesse `let name` em `makeWorker()`, então a busca iria para fora e pegaria a variável global, como podemos ver pela cadeia acima. Nesse caso, o resultado seria `"John"`.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# Which variables are available?
# Quais variáveis estão disponíveis?

The function `makeWorker` below makes another function and returns it. That new function can be called from somewhere else.
A função `makeWorker` abaixo cria outra função e a retorna. Essa nova função pode ser chamada de algum outro lugar.

Will it have access to the outer variables from its creation place, or the invocation place, or both?
Ela vai ter acesso às variáveis externas do seu lugar de criação, do lugar de invocação, ou dos dois?

```js
function makeWorker() {
Expand All @@ -19,11 +19,11 @@ function makeWorker() {

let name = "John";

// create a function
// cria uma função
let work = makeWorker();

// call it
work(); // what will it show?
// a chama

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.

// a chama (for "call it") reads as "the flame" in Portuguese — ambiguous comment. Suggest // chama a função or // chamando-a.

work(); // o que vai mostrar?
```

Which value it will show? "Pete" or "John"?
Qual valor ela vai mostrar? "Pete" ou "John"?
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
The answer: **0,1.**
A resposta: **0,1.**

Functions `counter` and `counter2` are created by different invocations of `makeCounter`.
As funções `counter` e `counter2` são criadas por invocações diferentes de `makeCounter`.

So they have independent outer Lexical Environments, each one has its own `count`.
Então elas têm Ambientes Léxicos externos independentes, cada uma com seu próprio `count`.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# Are counters independent?
# Os contadores são independentes?

Here we make two counters: `counter` and `counter2` using the same `makeCounter` function.
Aqui criamos dois contadores: `counter` e `counter2`, usando a mesma função `makeCounter`.

Are they independent? What is the second counter going to show? `0,1` or `2,3` or something else?
Eles são independentes? O que o segundo contador vai mostrar? `0,1` ou `2,3` ou outra coisa?

```js
function makeCounter() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Surely it will work just fine.
Com certeza vai funcionar direitinho.

Both nested functions are created within the same outer Lexical Environment, so they share access to the same `count` variable:
As duas funções aninhadas são criadas dentro do mesmo Ambiente Léxico externo, então elas compartilham acesso à mesma variável `count`:

```js run
function Counter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# Counter object
# Objeto contador

Here a counter object is made with the help of the constructor function.
Aqui um objeto contador é criado com a ajuda de uma função construtora.

Will it work? What will it show?
Vai funcionar? O que vai mostrar?

```js
function Counter() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
The result is **an error**.
O resultado é **um erro**.

The function `sayHi` is declared inside the `if`, so it only lives inside it. There is no `sayHi` outside.
A função `sayHi` é declarada dentro do `if`, então ela só vive dentro dele. Não existe `sayHi` fora.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
importance: 5

---
# Function in if
# Função no if

Look at the code. What will be the result of the call at the last line?
Olhe o código. Qual vai ser o resultado da chamada na última linha?

```js run
let phrase = "Hello";
Expand Down
Loading