Scope and closures
لم يُترجم بعد؛ يُعرض باللغة الإنجليزية
Scope decides where a name can be used: every function call gets its own box of variables, linked to the box outside it, and a lookup only ever walks outward. A function remembers the scope it was created in, so a variable can outlive the call that made it. Follow an eleven-line counter as makeCounter() builds a scope, hands back a closure, and that closure keeps count alive from one call to the next.
5 أسئلة سريعة
اختر إجابة لتعرف السبب. تُحفَظ نتيجتك مع تقدّمك.
01Inside the function returned by makeCounter, where does the engine find count?
The next() call's own scope has no count, so the lookup follows the outer link to the scope the function was created in, makeCounter's, where count lives.
02What does the program print?
Line 10 calls next() once (count becomes 1, the result is not used). Line 11 calls it again: count becomes 2, and console.log prints 2.
03makeCounter() has returned. Why is its scope, holding count, not thrown away?
A scope stays while something can still reach it. next → the function → its [[Environment]] → the makeCounter() scope. The next() call scopes, which nothing reaches after the call, can be thrown away.
04What happens if you add console.log(count) at the top level of the script?
Lookup only goes outward. The global scope has no count and nothing outside it, so the name is not found.
05You run const other = makeCounter(); other(); after the program. What does other() return?
Each call of makeCounter() makes a new scope with its own count = 0, so other has a separate counter and returns 1. next is untouched.
المسرد
- Scope
- The part of a program where a name can be used. JavaScript has global, function (one per call) and block scopes.
- Lexical scope
- A function's outer scope is decided by where it is written in the code, not by where it is called.
- Outer link
- Each scope's link to the scope around it. A lookup checks the current scope, then follows these links outward. The specification calls it [[OuterEnv]].
- [[Environment]]
- A hidden part of every function: a link to the scope the function was created in. A call of the function uses it as the new scope's outer link.
- Closure
- A function together with the scope it remembers. It can keep reading and changing that scope's variables after the outer call has ended.
- Global scope
- The outermost scope: names declared at the top level of a script.
- ReferenceError
- The error thrown when a name cannot be found in any scope along the chain.
- Garbage collection
- The engine's automatic removal of values that can no longer be reached, such as a finished call's scope that nothing refers to.
الملاحظات والمصادر
- The boxes are what the ECMAScript specification calls Environment Records. Each has an outer link ([[OuterEnv]]); a function call's record is made by NewFunctionEnvironment, and its outer link is the function's [[Environment]].
- In a script, const step and const next live in the global scope but do not become properties of window; the function declaration makeCounter does. Both kinds are visible to all the code in the page's scripts. In Node.js and in modules the top level is the module's own scope instead; it works the same way here.
- Function declarations are hoisted: the engine creates makeCounter before line 1 runs. const step and const next exist from the start too, but using them before their line throws a ReferenceError (the temporal dead zone).
- JavaScript has no command to free memory. A garbage collector removes values that can no longer be reached; when it runs is up to the engine. Engines may also keep only the variables a closure actually uses.
- let and const are also scoped to blocks: the code between { and }, such as an if or a for loop. This example has no inner blocks, so only function scopes appear.
- The program is real. Run node counter.js (or paste it into a browser console) and it prints 2.
اختبار يتاح بعد الخطوة الأخيرة.