I'm python developer.
In python, When you want to check whether a variable is already defined, you use dict
memo = {}
if 'a' not in memo:
memo['a'] = 'var_a'
javascript let keyword has similar functionality, it prevents re-defining.
let a = 1;
let a = 2; // SyntaxError
So how let achieves this functionality under the hood? Does V8 engine keeps some kind of HashMap of let variables?
Does V8 engine keeps some kind of HashMap of let variables?
Essentially, yes - though it's not a V8 thing in particular, it's something that all spec-compliant JavaScript engines must adhere to. It's called an environment record, which in this case is a "lexical environment", which is, to oversimplify, a collection of identifiers for a given scope and the values that the identifiers hold at that point.
When a function is evaluated, FunctionDeclarationInstantiation runs, which does, among many other things:
34. For each element d of lexDeclarations, do
a. (unimportant; omitted)
b. For each element dn of the BoundNames of d, do
i. If IsConstantDeclaration of d is true, then
1. Perform ! lexEnv.CreateImmutableBinding(dn, true).
ii. Else,
1. Perform ! lexEnv.CreateMutableBinding(dn, false).
The lexDeclarations include identifiers declared with let or const inside the function. This list cannot have duplicate entries as a result of an Early Errors requirement, which says, for blocks:
It is a Syntax Error if the LexicallyDeclaredNames of StatementList contains any duplicate entries.
Identifiers declared with vars are slightly different - they're not LexicallyDeclaredNames, but VarDeclaredNames instead, which have no requirement against being listed multiple times in a block. This doesn't result in duplicate var names being created multiple times in the environment because the duplicate declarations are explicitly skipped from the CreateMutableBinding call:
e. For each element n of varNames, do
i. If n is not an element of instantiatedVarNames, then
1. Append n to instantiatedVarNames.
2. Perform ! varEnv.CreateMutableBinding(n, false).
...