Why is let not slower than var?
综上所述,
因此,如果我们从这个答案中举一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | (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 (与var 一起声明)生活在整个function 内。j (与let 一起声明)只在for 循环内生存。
对我来说,这意味着在每次迭代之后,javascript除了声明和分配一个变量之外,在
但是如果我正确地阅读规范,还有很多:
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).
但在
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).
那么,为什么在运行下面的测试(我从前面提到的同一个问题中得出)时,
1 2 3 4 5 6 7 8 9 10 11 12 | (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({}); |
1 2 3 4 5 6 7 8 9 10 11 | TEST 1 var: 147.500ms let: 138.200ms TEST 2 var: 141.600ms let: 127.100ms TEST 3 var: 147.600ms let: 122.200ms |
我同意@derek會會會會會會會會會會會會
但是,如果是
在
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).
稍微额外的处理可能来自getValue。