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,5 +1,6 @@
The answer is: **Pete**.
الناتج هنا هو `‎"Pete"‎`.

A function gets outer variables as they are now, it uses the most recent values.
الدالة تحضر المتغيرات الخارجية كما هي الأن إنها تستخدم التي تم تعديلها مؤخراً.

القديمة لا تخزن بعد الأن لذلك الدالة تحصل علي أخر تحديث للمتغير إما عن طريق البيئة المعجمية الخاصة بها أو الخارجية

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.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ importance: 5

---

# Does a function pickup latest changes?
# هل تلتقط الدالة أخر التغييرات؟

الدالة sayHi تستخدم اسم مُتغير خارجي .
عندما تعمل الادلة أي منهم سيستخدم؟

The function sayHi uses an external variable name. When the function runs, which value is it going to use?

```js
let name = "John";
Expand All @@ -18,6 +20,7 @@ name = "Pete";
sayHi(); // what will it show: "John" or "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.
مواقف كهذه تعتبر شائعة إما بالنسبة غلي المتصفح أو الخادم. الادلة يمكن أن تتم مناداتها لاحقاً مثلاً بعد القيام ببعض الخطوات.

إذا السؤال هو هل ستشعر الدالة بالتغيير؟

So, the question is: does it pick up the latest changes?
51 changes: 28 additions & 23 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,15 @@

Let's examine what's done inside `makeArmy`, and the solution will become obvious.
لنُجري مسحًا شاملًا على ما يجري في `‎makeArmy‎`، حينها يظهر لنا الحل جليًا.

1. It creates an empty array `shooters`:
1. تُنشئ مصفوفة `‎shooters‎` فارغة:

```js
let shooters = [];
```
2. Fills it in the loop via `shooters.push(function...)`.
. تملأ المصفوفة في حلقة عبر `‎shooters.push(function...)‎`.

كلّ عنصر هو دالة، بهذا تكون المصفوفة الناتجة هكذا:

Every element is a function, so the resulting array looks like this:

```js no-beautify
shooters = [
Expand All @@ -25,17 +26,18 @@ Let's examine what's done inside `makeArmy`, and the solution will become obviou
];
```

3. The array is returned from the function.
3. تُعيد الدالة المصفوفة.

لاحقًا، يستلم استدعاء `‎army[5]()‎` العنصر `‎army[5]‎` من المصفوفة، وهي دالة فيستدعيها.

Then, later, the call to `army[5]()` will get the element `army[5]` from the array (it will be a function) and call it.
الآن، لماذا تعرض كلّ هذه الدوال نفس الناتج؟

Now why all such functions show the same?
يعزو ذلك إلى عدم وجود أيّ متغير محلي باسم `‎i‎` في دوال `‎shooter‎`. فحين تُستدعى هذه الدالة تأخذ المتغير `‎i‎` من البيئة المُعجمية الخارجية.

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.
وماذا ستكون قيمة `‎i‎`؟

What will be the value of `i`?
لو رأينا مصدر القيمة:

If we look at the source:

```js
function makeArmy() {
Expand All @@ -50,12 +52,12 @@ function makeArmy() {
...
}
```
كما نرى... «تعيش» القيمة في البيئة المُعجمية المرتبطة بدورة `‎makeArmy()‎` الحالية. ولكن متى استدعينا `‎army[5]()‎`، تكون دالة `‎makeArmy‎` قد أنهت مهمّتها فعلًا وقيمة `‎i‎` هي آخر قيمة، أي `‎10‎` (قيمة نهاية حلقة `‎while‎`).

...We can see that it lives in the lexical environment associated with the current `makeArmy()` run. But when `army[5]()` is called, `makeArmy` has already finished its job, and `i` has the last value: `10` (the end of `while`).
وبهذا تأخذ كلّ دوال `‎shooter‎` القيمة من البيئة المُعجمية الخارجية، ذات القيمة الأخيرة `‎i=10‎`.

As a result, all `shooter` functions get from the outer lexical envrironment the same, last value `i=10`.
يمكن أن نُصلح ذلك بنقل تعريف المتغير إلى داخل الحلقة:

We can fix it by moving the variable definition into the loop:

```js run demo
function makeArmy() {
Expand All @@ -65,8 +67,8 @@ function makeArmy() {
*!*
for(let i = 0; i < 10; i++) {
*/!*
let shooter = function() { // shooter function
alert( i ); // should show its number
let shooter = function() { // دالة مُطلق النار
alert( i ); // المفترض أن ترينا رقمها
};
shooters.push(shooter);
}
Expand All @@ -80,15 +82,17 @@ army[0](); // 0
army[5](); // 5
```

Now it works correctly, because every time the code block in `for (let i=0...) {...}` is executed, a new Lexical Environment is created for it, with the corresponding variable `i`.
الآن صارت تعمل كما يجب إذ في كلّ مرة تُنفّذ كتلة الشيفرة في `‎for (let i=0...) {...}‎`، يُنشئ المحرّك بيئة مُعجمية جديدة لها فيها متغير `‎i‎` المناسب لتلك الكتلة.

إذًا لنلخّص: قيمة `‎i‎` صارت «تعيش» أقرب للدالة من السابق. لم تعد في بيئة `‎makeArmy()‎` المُعجمية بل الآن في تلك البيئة المخصّصة لدورة الحلقة الحالية. هكذا صارت تعمل كما يجب.

So, the value of `i` now lives a little bit closer. Not in `makeArmy()` Lexical Environment, but in the Lexical Environment that corresponds the current loop iteration. That's why now it works.

![](lexenv-makearmy.svg)

Here we rewrote `while` into `for`.
أعدنا كتابة الشيفرة هنا وعوّضنا `‎while‎` بحلقة `‎for‎`.

يمكننا أيضًا تنفيذ حيلة أخرى. لنراها لنفهم الموضوع أكثر:

Another trick could be possible, let's see it for better understanding of the subject:

```js run
function makeArmy() {
Expand All @@ -99,8 +103,8 @@ function makeArmy() {
*!*
let j = i;
*/!*
let shooter = function() { // shooter function
alert( *!*j*/!* ); // should show its number
let shooter = function() { // دالة مُطلق النار
alert( *!*j*/!* ); // (*) المفترض أن ترينا رقمها
};
shooters.push(shooter);
i++;
Expand All @@ -115,6 +119,7 @@ army[0](); // 0
army[5](); // 5
```

The `while` loop, just like `for`, makes a new Lexical Environment for each run. So here we make sure that it gets the right value for a `shooter`.
كما حلقة `‎for‎`، فحلقة `‎while‎` تصنع بيئة مُعجمية جديدة لكلّ دورة، وهكذا نتأكّد بأن تكون قيمة `‎shooter‎` صحيحة.

باختصار ننسخ القيمة `‎let j = i‎` وهذا يصنع المتغير `‎j‎` المحلي داخل الحلقة وينسخ قيمة `‎i‎` إلى نفسه. تُنسخ الأنواع الأولية «حسب قيمتها» _By value_، لذا بهذا نأخذ نسخة كاملة مستقلة تمامًا عن `‎i‎`، ولكنّها مرتبطة بالدورة الحالية في الحلقة.

We copy `let j = i`. This makes a loop body local `j` and copies the value of `i` to it. Primitives are copied "by value", so we actually get a complete independent copy of `i`, belonging to the current loop iteration.
19 changes: 10 additions & 9 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,20 +2,20 @@ importance: 5

---

# Army of functions
### جيش من الدوال

The following code creates an array of `shooters`.
تصنع الشيفرة الآتية مصفوفة من مُطلقي النار `‎shooters`.

Every function is meant to output its number. But something is wrong...
يفترض أن تكتب لنا كلّ دالة رقم هويّتها، ولكن ثمّة خطب فيها...

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

let i = 0;
while (i < 10) {
let shooter = function() { // shooter function
alert( i ); // should show its number
let shooter = function() { // دالة مُطلق النارn
alert( i ); // المفترض أن ترينا رقمها
};
shooters.push(shooter);
i++;
Expand All @@ -26,10 +26,11 @@ 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](); // مُطلق النار بالهويّة 0 يقول أنّه 10
army[5](); // ‫مُطلق النار بالهويّة 5 يقول أنّه 10...
// ... كلّ مُطلقي النار يقولون 10 بدل هويّاتهم 0 فَـ 1 فَـ 2 فَـ 3...

```

Why do all of the shooters show the same value? Fix the code so that they work as intended.
لماذا هويّة كلّ مُطلق نار نفس البقية؟ أصلِح الشيفرة لتعمل كما ينبغي أن تعمل.

Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
The answer is: **Pete**.
أفترض الآن بأنّ إجابة السؤال الثاني في أول الفصل ستكون جليّة.

دالة `‎work()‎` في الشيفرة أدناه تأخذ الاسم `‎name‎` من مكانه الأصل عبر إشارة البيئة المُعجمية الخارجية إليه:

The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference:

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

So, the result is `"Pete"` here.

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"`.
إذًا، فالناتج هنا هو `‎"Pete"‎`.

ولكن لو لم نكتب `‎let name‎` في `‎makeWorker()‎` فسينتقل البحث إلى خارج الدالة تلك ويأخذ القيمة العمومية كما نرى من السلسلة أعلاه. في تلك الحالة سيكون الناتج `‎"John"‎`.

Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ importance: 5

---

# Which variables are available?
# أي من المُتغيرات متاح؟

The function `makeWorker` below makes another function and returns it. That new function can be called from somewhere else.
الدالة `makeWorker` بالإسفل تصنع دالة أخري وتعيدها. هذه الدالة المُعادة يمكن مناداتها من أي مكان.

هل ستحصل علي حق الوصول إلي المتغيرات الخارجية من موقع بنائها أم من موقع مناداتها أو من الاثنين؟

Will it have access to the outer variables from its creation place, or the invocation place, or both?

```js
function makeWorker() {
Expand All @@ -25,5 +26,5 @@ let work = makeWorker();
// call it
work(); // what will it show?
```
أي قيمة سوف تظهر؟ "Pete" أم "John"؟

Which value it will show? "Pete" or "John"?
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
The answer: **0,1.**
الإجابة هي: **0,1**.

Functions `counter` and `counter2` are created by different invocations of `makeCounter`.
صنعنا الدالتين `‎counter‎` و `‎counter2‎` باستدعاءين `‎makeCounter‎` مختلفين تمامًا.

لذا فلكلّ منهما بيئات مُعجمية خارجية مستقلة عن بعضها، ولكلّ منهما متغير `‎count‎` مستقل عن الثاني.

So they have independent outer Lexical Environments, each one has its own `count`.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
importance: 5
_الأهمية: 5_

---

# Are counters independent?
### هل العدّادات مستقلة عن بعضها البعض؟

Here we make two counters: `counter` and `counter2` using the same `makeCounter` function.
صنعنا هنا عدّادين اثنين `‎counter‎` و `‎counter2‎` باستعمال ذات الدالة `‎makeCounter‎`.

Are they independent? What is the second counter going to show? `0,1` or `2,3` or something else?
هل هما مستقلان عن بعضهما البعض؟ ما الذي سيعرضه العدّاد الثاني؟ `‎0,1‎` أم `‎2,3‎` أم ماذا؟

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

Surely it will work just fine.
طبعًا، ستعمل كما يجب.

صُنعت الدالتين المتداخلتين في نفس البيئة المُعجمية الخارجية، بهذا تتشاركان نفس المتغير `‎count‎` وتصلان إليه:

Both nested functions are created within the same outer Lexical Environment, so they share access to the same `count` variable:

```js run
function Counter() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
importance: 5
_الأهمية: 5_

---

# Counter object
### كائن عد

Here a counter object is made with the help of the constructor function.
هنا صنعنا كائن عدّ بمساعدة دالة مُنشئة _Constructor Function_.

هل ستعمل؟ ماذا سيظهر؟

Will it work? What will it show?

```js
function Counter() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
The result is **an error**.
الناتج هو: **خطأ**.

The function `sayHi` is declared inside the `if`, so it only lives inside it. There is no `sayHi` outside.
صُرّح عن الدالة `‎sayHi‎` داخل الشرط `‎if‎` وتعيش فيه فقط لا غير. ما من دالة `‎sayHi‎` خارجية.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@

# Function in if
### دالة في شرط if


طالِع الشيفرة أسفله. ما ناتج الاستدعاء في آخر سطر؟

Look at the code. What will be the result of the call at the last line?

```js run
let phrase = "Hello";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
For the second parentheses to work, the first ones must return a function.
ليعمل القوسين الثانيين، يجب أن يُعيد الأوليين دالة.

هكذا:

Like this:

```js run
function sum(a) {
Expand Down
11 changes: 6 additions & 5 deletions 1-js/06-advanced-functions/03-closure/6-closure-sum/task.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
importance: 4
_الأهمية: 4_

---

# Sum with closures
### المجموع باستعمال المُنغلِقات

Write function `sum` that works like this: `sum(a)(b) = a+b`.
اكتب الدالة `‎sum‎` لتعمل هكذا: `sum(a)(b) = a+b`.

Yes, exactly this way, using double parentheses (not a mistype).
نعم هكذا تمامًا باستعمال قوسين اثنين (ليست خطأً مطبعيًا).

مثال:

For instance:

```js
sum(1)(2) = 3
Expand Down
26 changes: 14 additions & 12 deletions 1-js/06-advanced-functions/03-closure/7-let-scope/solution.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
The result is: **error**.

Try running it:
الناتج: **خطأ**.

جرب الكود للتأكد:


```js run
let x = 1;

function func() {
*!*
console.log(x); // ReferenceError: Cannot access 'x' before initialization
console.log(x); // ReferenceError: لا نستطيع الوصول لـ 'x' قبل إعطائها قيمة
*/!*
let x = 2;
}

func();
```

In this example we can observe the peculiar difference between a "non-existing" and "unitialized" variable.
في هذا المثال نستشف الفرق بين **غير موجود** و **غير معرف بقيمة**

كما قرأت في هذه المقالة [](info:closure), المتغير أولاً يكون في حالة **غير معرف بقيمة** عند اللحظة الذي يتم فيها تشغيل الكتلة كلها التي تحتوي علي المتغير. وتظل هكذا حتي جملة `let`.

As you may have read in the article [](info:closure), a variable starts in the "uninitialized" state from the moment when the execution enters a code block (or a function). And it stays uninitalized until the corresponding `let` statement.
أو بطريقة أخرى, المُتغير تقنياً موجود, لكن ا تستطيع الوصول له قبل `let`.

In other words, a variable technically exists, but can't be used before `let`.
الكود فى الأعلي وضح ذلك.

The code above demonstrates it.

```js
function func() {
*!*
// the local variable x is known to the engine from the beginning of the function,
// but "unitialized" (unusable) until let ("dead zone")
// hence the error
// المتغير المحلي X يعتبر معروف للمحرك من البداية, لكن **غير معرف بقيمة** تظل حتي let
// لذلك هناك خطأ
*/!*

console.log(x); // ReferenceError: Cannot access 'x' before initialization
console.log(x); // ReferenceError: لا نستطيع الوصول لـ 'x' قبل إعطائها قيمة

let x = 2;
}
```
هذه المنطقة من المتغيرات المؤقتة الغير مستخدمة من بداية الكود حتي `let` تسمي **بالمنطقة الميتة**

This zone of temporary unusability of a variable (from the beginning of the code block till `let`) is sometimes called the "dead zone".
Loading