Skip to content
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

Variable scope, closure #204

Open
wants to merge 85 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
68a7885
Update article.md
ImVietnam Mar 11, 2023
6df7986
Update article.md
ImVietnam Mar 11, 2023
6612812
Update article.md
ImVietnam Mar 11, 2023
ef2e635
Update article.md
ImVietnam Mar 15, 2023
e43b1f7
Update article.md
ImVietnam Mar 15, 2023
4ea135d
Update closure-function-declaration.svg
ImVietnam Mar 15, 2023
9bfddd4
Update closure-function-declaration.svg
ImVietnam Mar 15, 2023
f7be4f0
Update article.md
ImVietnam Mar 16, 2023
e1eaab5
Update closure-makecounter-environment.svg
ImVietnam Mar 16, 2023
b20946b
Update closure-makecounter-environment.svg
ImVietnam Mar 16, 2023
c84df45
Update closure-makecounter-nested-call-2.svg
ImVietnam Mar 16, 2023
dcafb7b
Update closure-makecounter-nested-call-2.svg
ImVietnam Mar 16, 2023
b33c5eb
Update closure-function-declaration.svg
ImVietnam Mar 16, 2023
b6a548f
Update closure-makecounter-environment.svg
ImVietnam Mar 16, 2023
8a4eede
Update closure-makecounter-nested-call.svg
ImVietnam Mar 16, 2023
b63ae2c
Update closure-makecounter-nested-call.svg
ImVietnam Mar 16, 2023
57be90e
Update closure-makecounter-nested-call.svg
ImVietnam Mar 16, 2023
714290e
Update closure-makecounter-nested-call.svg
ImVietnam Mar 16, 2023
929d822
Update closure-makecounter-nested-call.svg
ImVietnam Mar 16, 2023
00f9f89
Update closure-makecounter-nested-call.svg
ImVietnam Mar 16, 2023
e2345d6
Update closure-makecounter-environment.svg
ImVietnam Mar 16, 2023
a7651b3
Update closure-makecounter-nested-call-2.svg
ImVietnam Mar 16, 2023
942b855
Update closure-makecounter-nested-call-2.svg
ImVietnam Mar 16, 2023
091c5b4
Update article.md
ImVietnam Mar 16, 2023
ae48d63
Update closure-function-declaration.svg
ImVietnam Mar 16, 2023
937e670
Update closure-function-declaration.svg
ImVietnam Mar 16, 2023
3a56f9c
Update closure-makecounter-environment.svg
ImVietnam Mar 16, 2023
86d3653
Update closure-makecounter-nested-call-2.svg
ImVietnam Mar 16, 2023
1b3695f
Update closure-makecounter-nested-call.svg
ImVietnam Mar 16, 2023
4f7b3a6
Update closure-makecounter.svg
ImVietnam Mar 16, 2023
c7f8584
Update closure-variable-phrase.svg
ImVietnam Mar 16, 2023
2cb5bff
Update lexenv-if.svg
ImVietnam Mar 16, 2023
9ec38bb
Update lexenv-if.svg
ImVietnam Mar 16, 2023
3c11ee1
Update lexenv-nested-makecounter-1.svg
ImVietnam Mar 16, 2023
78ce0b6
Update lexenv-nested-makecounter-2.svg
ImVietnam Mar 16, 2023
0324e13
Update lexenv-nested-makecounter-3.svg
ImVietnam Mar 16, 2023
f06eecc
Update lexenv-nested-makecounter-4.svg
ImVietnam Mar 20, 2023
a434eda
Update lexenv-nested-makecounter-5.svg
ImVietnam Apr 9, 2023
8046ccf
Update closure-makecounter-environment.svg
ImVietnam Apr 9, 2023
a0c22c3
Update article.md
ImVietnam May 22, 2023
35ebe02
Update closure-function-declaration.svg
ImVietnam May 22, 2023
f163cc1
Update closure-function-declaration.svg
ImVietnam May 22, 2023
2de5a79
Update lexenv-nested-makecounter-6.svg
ImVietnam Jun 5, 2023
2dc9df3
Update lexenv-nested-makecounter-6.svg
ImVietnam Jun 5, 2023
da07960
Update lexical-environment-global-2.svg
ImVietnam Jun 5, 2023
933bdf2
Update lexical-environment-global-3.svg
ImVietnam Jun 5, 2023
4680376
Update lexical-environment-global.svg
ImVietnam Jun 5, 2023
08fb0e6
Update lexical-environment-simple-lookup.svg
ImVietnam Jun 5, 2023
c52ca7a
Update lexical-environment-simple.svg
ImVietnam Jun 5, 2023
0ccb59e
Update task.md
ImVietnam Jun 5, 2023
e08d150
Update solution.md
ImVietnam Jun 5, 2023
586002a
Update task.md
ImVietnam Jun 5, 2023
4b1c1a4
Update solution.md
ImVietnam Jun 5, 2023
a53cfc9
Update lexenv-makearmy-while-fixed.svg
ImVietnam Jun 5, 2023
2f0ef5f
Update lexenv-makearmy-for-fixed.svg
ImVietnam Jun 5, 2023
d1388ba
Update lexenv-makearmy-empty.svg
ImVietnam Jun 5, 2023
4712bdb
Update solution.js
ImVietnam Jun 5, 2023
be8977f
Update source.js
ImVietnam Jun 5, 2023
ab8799e
Update task.md
ImVietnam Jun 5, 2023
de8624e
Update task.md
ImVietnam Jun 5, 2023
9d06bfa
Update solution.md
ImVietnam Jun 5, 2023
251255c
Update lexenv-nested-work.svg
ImVietnam Jun 5, 2023
1efc4b9
Update task.md
ImVietnam Jun 5, 2023
5b1b1ee
Update solution.md
ImVietnam Jun 5, 2023
9bd3d03
Update task.md
ImVietnam Jun 5, 2023
93fcf08
Update solution.md
ImVietnam Jun 5, 2023
9462ff1
Update task.md
ImVietnam Jun 5, 2023
daffeaf
Update solution.md
ImVietnam Jun 5, 2023
9939895
Update task.md
ImVietnam Jun 5, 2023
f5eec0e
Update task.md
ImVietnam Jun 5, 2023
be7da66
Update solution.md
ImVietnam Jun 5, 2023
2a43201
Update task.md
ImVietnam Jun 5, 2023
492335b
Update solution.md
ImVietnam Jun 5, 2023
09d2e63
Update task.md
ImVietnam Jun 5, 2023
db7d52c
Update task.md
ImVietnam Jun 5, 2023
9e754ad
Update solution.md
ImVietnam Jun 5, 2023
e575ae5
Update source.js
ImVietnam Jun 5, 2023
0a5c3fc
Update task.md
ImVietnam Jun 5, 2023
08ef596
Update source.js
ImVietnam Jun 5, 2023
c50d02b
Update solution.md
ImVietnam Jun 5, 2023
56deede
Update solution.md
ImVietnam Jun 5, 2023
8502b4d
Update solution.md
ImVietnam Jun 5, 2023
3af0ffb
Update solution.md
ImVietnam Jun 5, 2023
3718a0b
Merge branch 'javascript-tutorial:master' into patch-26
ImVietnam Jun 9, 2023
fb9352a
Merge branch 'javascript-tutorial:master' into patch-26
ImVietnam Aug 2, 2023
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**.
Đáp án là: **Pete**.

A function gets outer variables as they are now, it uses the most recent values.
Một hàm nhận các biến bên ngoài như hiện tại, nó sử dụng các giá trị gần đây nhất.

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.
Giá trị biến cũ không được lưu ở bất cứ đâu. Khi một hàm muốn một biến, nó sẽ lấy giá trị hiện tại từ Lexical Environment của chính nó hoặc environment bên ngoài.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ importance: 5

---

# Does a function pickup latest changes?
# Hàm có nhận thay đổi mới nhất không?

The function sayHi uses an external variable name. When the function runs, which value is it going to use?
Hàm sayHi sử dụng tên biến ngoài. Khi hàm chạy, nó sẽ sử dụng giá trị nào?

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

name = "Pete";

sayHi(); // what will it show: "John" or "Pete"?
sayHi(); // nó sẽ hiển thị gì: "John" hay "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.
Những tình huống như vậy là phổ biến cả trong phát triển trình duyệt và phía máy chủ. Một hàm có thể được lên lịch để thực thi muộn hơn so với khi nó được tạo, chẳng hạn như sau một hành động của người dùng hoặc một yêu cầu mạng.

So, the question is: does it pick up the latest changes?
Vì vậy, câu hỏi là: nó có nhận những thay đổi mới nhất không?
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() { // hàm shooter
alert( i ); // nên hiện số của nó
};
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() { // hàm shooter
alert( i ); // nên hiện số của nó
};
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](); // shooter số 0 hiển thị 10
army[5](); // và số 5 cũng ra 10...
// ... tất cả các shooter hiển thị 10 thay vì số của chúng 0, 1, 2, 3...
*/
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.
54 changes: 27 additions & 27 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.
Hãy xem xét chính xác điều gì xảy ra bên trong `makeArmy` và giải pháp sẽ trở nên rõ ràng.

1. It creates an empty array `shooters`:
1. Nó tạo ra một array `shooters` trống:

```js
let shooters = [];
```
2. Fills it with functions via `shooters.push(function)` in the loop.
2. Điền vào nó các hàm thông qua `shooters.push(function)` trong vòng lặp.

Every element is a function, so the resulting array looks like this:
Mỗi phần tử là một hàm, vì vậy array kết quả trông như thế này:

```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. Array được trả về từ hàm.

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.
Sau đó, sau đó, cuộc gọi đến bất kỳ thành viên nào, ví dụ:. `army[5]()` sẽ lấy phần tử `army[5]` từ array (là một hàm) và gọi nó.

Now why do all such functions show the same value, `10`?
Bây giờ tại sao tất cả các chức năng như vậy hiển thị cùng một giá trị, `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.
Đó là bởi vì không có biến cục bộ `i` bên trong các hàm `shooter`. Khi một hàm như vậy được gọi, nó sẽ lấy `i` từ lexical environment bên ngoài của nó.

Then, what will be the value of `i`?
Khi đó, giá trị của `i` sẽ là bao nhiêu?

If we look at the source:
Nếu chúng ta nhìn vào nguồn:

```js
function makeArmy() {
...
let i = 0;
while (i < 10) {
let shooter = function() { // shooter function
alert( i ); // should show its number
let shooter = function() { // hàm shooter
alert( i ); // nên hiển thị số của nó
};
shooters.push(shooter); // add function to the array
shooters.push(shooter); // thêm hàm vào 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`).
Chúng ta có thể thấy rằng tất cả các hàm `shooter` đều được tạo trong lexical environment của hàm `makeArmy()`. Nhưng khi `army[5]()` được gọi, `makeArmy` đã hoàn thành công việc của nó và giá trị cuối cùng của `i` `10` (`while` dừng ở `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`.
Kết quả là, tất cả các hàm `shooter` nhận cùng một giá trị từ lexical environment bên ngoài và đó là giá trị cuối cùng, `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:
Như bạn có thể thấy ở trên, trên mỗi lần lặp của khối `while {...}`, một lexical environment mới được tạo. Vì vậy, để khắc phục điều này, chúng ta có thể sao chép giá trị của `i` vào một biến trong khối `while {...}`, như sau:

```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() { // hàm shooter
alert( *!*j*/!* ); // nên hiển thị số của nó
};
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
// Bây giờ mã hoạt động đúng
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.
Ở đây `let j = i` khai báo một biến "lặp cục bộ" `j` và sao chép `i` vào đó. Các bản gốc được sao chép "theo giá trị", vì vậy chúng ta thực sự nhận được một bản sao độc lập của `i`, thuộc về phép lặp vòng lặp hiện tại.

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:

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

Such a problem could also be avoided if we used `for` in the beginning, like this:
Vấn đề như vậy cũng có thể tránh được nếu chúng ta sử dụng `for` ngay từ đầu, như sau:

```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() { // hàm shooter
alert( i ); // nên hiển thị số của nó
};
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.
Điều đó về cơ bản là giống nhau, bởi vì `for` trên mỗi lần lặp tạo ra một lexical environment mới, với biến riêng `i`. Vì vậy, `shooter` được tạo trong mỗi lần lặp tham chiếu `i` của chính nó, từ chính lần lặp đó.

![](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?
Bây giờ, vì bạn đã bỏ ra rất nhiều công sức để đọc nó, và công thức cuối cùng rất đơn giản - chỉ cần sử dụng `for`, bạn có thể tự hỏi -- nó có đáng không?

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.
Chà, nếu bạn có thể dễ dàng trả lời câu hỏi, bạn sẽ không đọc lời giải. Vì vậy, hy vọng nhiệm vụ này đã giúp bạn hiểu mọi thứ tốt hơn một chút.

Besides, there are indeed cases when one prefers `while` to `for`, and other scenarios, where such problems are real.
Bên cạnh đó, thực sự có những trường hợp khi một người thích `while` hơn là `for`, và các tình huống khác, trong đó các vấn đề như vậy là có thật.

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
# Đội quân hàm

The following code creates an array of `shooters`.
Đoạn mã sau tạo ra một array của `shooters`.

Every function is meant to output its number. But something is wrong...
Mọi chức năng đều xuất ra số của nó. Nhưng có gì đó không ổn ...

```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() { // tạo một hàm shooter,
alert( i ); // điều đó nên hiển thị số của nó
};
shooters.push(shooter); // and add it to the array
shooters.push(shooter); // và thêm nó vào array
i++;
}

// ...and return the array of shooters
// ....và trả lại array shooter
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.
// tất cả các shooter hiển thị 10 thay vì số của chúng 0, 1, 2, 3...
army[0](); // 10 từ shooter số 0
army[1](); // 10 từ shooter số 1
army[2](); // 10 ... vân vân.
*/!*
```

Why do all of the shooters show the same value?
Tại sao tất cả các shooter hiển thị cùng một giá trị?

Fix the code so that they work as intended.
Sửa mã để chúng hoạt động như dự định.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
The answer is: **Pete**.
Đáp án là: **Pete**.

The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference:
Hàm `work()` trong đoạn mã bên dưới lấy `name` từ nơi xuất phát của nó thông qua tham chiếu lexical environment bên ngoài:

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

So, the result is `"Pete"` here.
Vì vậy, kết quả là `"Pete"` ở đây.

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"`.
Nhưng nếu không có `let name` trong `makeWorker()`, thì tìm kiếm sẽ ra bên ngoài và lấy biến cục bộ như chúng ta có thể thấy từ chuỗi bên trên. Trong trường hợp đó, kết quả sẽ là `"John"`.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# Which variables are available?
# Những biến nào có sẵn?

The function `makeWorker` below makes another function and returns it. That new function can be called from somewhere else.
Hàm `makeWorker` bên dưới tạo một hàm khác và trả về hàm đó. Hàm mới đó có thể được gọi từ một nơi khác.

Will it have access to the outer variables from its creation place, or the invocation place, or both?
Nó sẽ có quyền truy cập vào các biến bên ngoài từ nơi tạo của nó, hay nơi gọi, hay cả hai?

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

let name = "John";

// create a function
// tạo một hàm
let work = makeWorker();

// call it
work(); // what will it show?
// gọi nó
work(); // nó sẽ hiển thị những gì?
```

Which value it will show? "Pete" or "John"?
Nó sẽ hiển thị giá trị nào? "Pete" hay "John"?
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
The answer: **0,1.**
Đáp án: **0,1.**

Functions `counter` and `counter2` are created by different invocations of `makeCounter`.
Các hàm `counter` `counter2` được tạo bởi các lệnh gọi khác nhau của `makeCounter`.

So they have independent outer Lexical Environments, each one has its own `count`.
Vì vậy, chúng có các Lexical Environment bên ngoài độc lập, mỗi environment có `count` riêng.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# Are counters independent?
# Bộ đếm có độc lập không?

Here we make two counters: `counter` and `counter2` using the same `makeCounter` function.
Ở đây chúng ta tạo hai bộ đếm: `counter` `counter2` bằng cách sử dụng cùng hàm `makeCounter`.

Are they independent? What is the second counter going to show? `0,1` or `2,3` or something else?
Chúng có độc lập không? Bộ đếm thứ hai sẽ hiển thị là gì? `0,1` hay `2,3` hay cái gì khác?

```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.
Chắc chắn nó sẽ hoạt động tốt.

Both nested functions are created within the same outer Lexical Environment, so they share access to the same `count` variable:
Cả hai hàm lồng nhau đều được tạo trong cùng một Lexical Environment bên ngoài, vì vậy chúng chia sẻ quyền truy cập vào cùng một biến `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
# Đối tượng bộ đếm

Here a counter object is made with the help of the constructor function.
Ở đây, một đối tượng bộ đếm được tạo với sự trợ giúp của hàm tạo.

Will it work? What will it show?
Nó có hoạt động không? Nó sẽ hiển thị cái gì?

```js
function Counter() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
The result is **an error**.
Kết quả là **một lỗi**.

The function `sayHi` is declared inside the `if`, so it only lives inside it. There is no `sayHi` outside.
Hàm `sayHi` được khai báo bên trong `if`, vì vậy nó chỉ tồn tại bên trong nó. Không có `sayHi` bên ngoài.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# Function in if
# Hàm trong if

Look at the code. What will be the result of the call at the last line?
Nhìn vào mã. Cái gì sẽ là kết quả của cuộc gọi ở dòng cuối cùng?

```js run
let phrase = "Hello";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
For the second parentheses to work, the first ones must return a function.
Để các dấu ngoặc đơn thứ hai hoạt động, các dấu ngoặc đơn đầu tiên phải trả về một hàm.

Like this:
Như thế này:

```js run
function sum(a) {

return function(b) {
return a + b; // takes "a" from the outer lexical environment
return a + b; // lấy "a" từ lexical environment bên ngoài
};

}
Expand Down
8 changes: 4 additions & 4 deletions 1-js/06-advanced-functions/03-closure/6-closure-sum/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ importance: 4

---

# Sum with closures
# Tổng có bao đóng

Write function `sum` that works like this: `sum(a)(b) = a+b`.
Viết hàm `sum` hoạt động như sau: `sum(a)(b) = a+b`.

Yes, exactly this way, using double parentheses (not a mistype).
Vâng, chính xác theo cách này, sử dụng dấu ngoặc kép (không phải gõ nhầm).

For instance:
Ví dụ:

```js
sum(1)(2) = 3
Expand Down
Loading