I'm trying to understand this unexplained code from Eloquent Javascript :
function trackKeys(keys) {
let down = Object.create(null);
function track(event) {
if (keys.includes(event.key)) {
down[event.key] = event.type == "keydown";
event.preventDefault();
}
}
window.addEventListener("keydown", track);
window.addEventListener("keyup", track);
return down;
}
var arrowKeys =
trackKeys(["ArrowLeft", "ArrowRight", "ArrowUp"]);
I think I understand how the inner function track
will maintain a reference to down
and keys
because it is a closure, but I'm lost at return down;
Will that return value be a reference to the exact same down
the callbacks are accessing? I don't understand; I thought local variables could only be accessed by inner functions?
Follow-up: what if down were a primitive data type and not an object, would this still work?
Thanks!
CodePudding user response:
The function initializes the variable down
as an object.
So within the function, down
is a variable that points to a certain object.
When the function returns down
, it returns a reference to the object, meaning that the object becomes accessible through the return of the function.
If down
were primitive, then this would not work since the function would only return a primitive value rather than a reference to an object.
CodePudding user response:
TLDR: Saying "a variable is returned" is ambiguous due to the inherent imprecision of human language. It does not mean that the variable-pairing of identifier and value is returned. It means the value of the variable is returned. In this case the value of the reference to the object (created by Object.create(null)
) is returned.
Will that return value be a reference to the exact same
down
the callbacks are accessing?
Yes.
I thought local variables could only be accessed by inner functions?
A variable is a pairing of an identifier (ie. the name of the variable) and a value.
Scope is the region of code over which an identifier (in this case "down
") has a specific meaning.
The scope of an identifier is determined by the way in which the variable is declared (const
/let
/var
/implicit in non-strict mode). Variable down
is declared using let
; its scope is therefore the nearest containing block, which is the function trackKeys
.
Functions declared inside trackKeys
will close over down
via the built-in closure-forming mechanism of JavaScript, and will therefore share the meaning of the identifier "down".
Note: if inner functions or blocks also declare their own variable named "down"
these inner variables will either result in an error (var
in a non-function block in strict mode, duplicate declaration), do nothing (var
in non-strict mode in a non-function block), or shadow (hide from view) the outer variable (let
/const
).
Returning down
does not change the scope of the identifier down
. Trying to refer to "down" outside trackKeys
will continue to error or return undefined depending on whether you are in strict mode. Returning the value of down
does, however, make this value available outside trackKeys
.