To make an extreme sum up, the difference between var
and let
is their life within a scope.
So if we are to take the example from this answer:
(function() {
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(`i: ${i}`);
}, i * 100);
}
// 5, 5, 5, 5, 5
for (let j = 0; j < 5; j++) {
setTimeout(function() {
console.log(`j: ${j}`);
}, 1000 + j * 100);
}
// 0, 1, 2, 3, 4
}());
i
(declared with var
) lives within the entire function
j
(declared with let
) lives only within the for
loop.To me, this means that javascript, after each iteration, besides declaring and assigning to a variable, in the case of let
it also needs to perform an extra step: clean up j
But if I'm reading the specs right, there's so much more:
var
, these steps are performed:IterationStatement : for ( Expressionopt ; Expressionopt ; Expressionopt ) Statement
- If the first Expression is present, then
- Let exprRef be the result of evaluating the first Expression.
- Let exprValue be GetValue(exprRef).
- ReturnIfAbrupt(exprValue).
- Return ForBodyEvaluation(the second Expression, the third Expression, Statement, « », labelSet).
But in the case of let
, a whopping list of 12 steps are performed, including creations of new declarative environments.
IterationStatement : for ( LexicalDeclaration Expressionopt ; Expressionopt ) Statement
- Let oldEnv be the running execution context’s LexicalEnvironment.
- Let loopEnv be NewDeclarativeEnvironment(oldEnv).
- Let isConst be the result of performing IsConstantDeclaration of > 1. LexicalDeclaration.
- Let boundNames be the BoundNames of LexicalDeclaration.
- For each element dn of boundNames do
- If isConst is true, then
- Perform loopEnv.CreateImmutableBinding(dn, true).
- Else,
- Perform loopEnv.CreateMutableBinding(dn, false).
- Assert: The above call to CreateMutableBinding will never return an abrupt completion.
- Set the running execution context’s LexicalEnvironment to loopEnv.
- Let forDcl be the result of evaluating LexicalDeclaration.
- If forDcl is an abrupt completion, then
- Set the running execution context’s LexicalEnvironment to oldEnv.
- Return Completion(forDcl).
- If isConst is false, let perIterationLets be boundNames otherwise let perIterationLets be « ».
- Let bodyResult be ForBodyEvaluation(the first Expression, the second Expression, Statement, perIterationLets, labelSet).
- Set the running execution context’s LexicalEnvironment to oldEnv.
- Return Completion(bodyResult).
So why is it that when running the following test (which I took from the same question I previously referenced) , var
performs slower than let
, and not vice versa, as I'm expecting?
(function() {
let varTime = performance.now()
for (var i = 0; i < 100000000; i++) {}
varTime = performance.now() - varTime;
console.log('var', varTime)
let letTime = performance.now()
for (let i = 0; i < 100000000; i++) {}
letTime = performance.now() - letTime;
console.log('let', letTime)
}).call({});
TEST 1
var: 147.500ms
let: 138.200ms
TEST 2
var: 141.600ms
let: 127.100ms
TEST 3
var: 147.600ms
let: 122.200ms
I agreed with @Derek 朕會功夫 that it is really hard to reason without diving down into the implementation.
But, you might have missed the some of the steps in case of var
:
In the case of var
, there are actually more steps performed:
IterationStatement : for ( Expressionopt ; Expressionopt ; Expressionopt ) Statement
- If the first Expression is present, then
- Let exprRef be the result of evaluating the first Expression.
- Let exprValue be GetValue(exprRef).
- ReturnIfAbrupt(V).
- If Type(V) is not Reference, return V.
- Let base be GetBase(V).
- If IsUnresolvableReference(V), throw a ReferenceError exception.
- If IsPropertyReference(V), then
- If HasPrimitiveBase(V) is true, then
- Assert: In this case, base will never be null or undefined.
- Let base be ToObject(base).
- Return base.[[Get]](GetReferencedName(V), GetThisValue(V)).
- Else base must be an Environment Record,
- Return base.GetBindingValue(GetReferencedName(V), IsStrictReference(V)) (see 8.1.1).
- ReturnIfAbrupt(exprValue).
- Return ForBodyEvaluation(the second Expression, the third Expression, Statement, « », labelSet).
The slightly additional processing could be from GetValue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With