为什么不比var慢呢?

时间:2018-07-26 05:35:57

标签: javascript performance var let

总结一下,the difference between var and let是他们在一定范围内的生活。

因此,如果我们以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(用var声明)生活在整个function
  • j(用let声明)仅位于for循环内。

对我来说,这意味着javascript,在每次迭代之后,除了声明和分配给变量外,对于let,它还需要执行一个额外的步骤:清理j

但是,如果我没看错the specs,那还有更多:

  1. 对于var,将执行以下步骤:
  

IterationStatement:用于(Expressionopt; Expressionopt; Expressionopt)语句

     
      
  1. 如果存在第一个表达式,则      
        
    • 让exprRef为评估第一个表达式的结果。
    •   
    • 让exprValue为GetValue(exprRef)。
    •   
    • ReturnIfAbrupt(exprValue)。
    •   
  2.   
  3. 返回ForBodyEvaluation(第二个表达式,第三个表达式,语句,«»,labelSet)。
  4.   
  1. 但是在let的情况下,将执行12个步骤的庞大列表,包括创建新的声明性环境。

      

    IterationStatement:用于(LexicalDeclaration Expressionopt; Expressionopt)语句

         
        
    1. 让oldEnv成为正在运行的执行上下文的LexicalEnvironment。
    2.   
    3. 让loopEnv为NewDeclarativeEnvironment(oldEnv)。
    4.   
    5. 让isConst是执行>1。LexicalDeclaration的IsConstantDeclaration的结果。
    6.   
    7. 让boundNames为LexicalDeclaration的BoundNames。
    8.   
    9. 对于boundNames的每个元素dn      
          
      • 如果isConst为true,则      
            
        • 执行loopEnv.CreateImmutableBinding(dn,true)。
        •   
      •   
      • 其他,      
            
        • 执行loopEnv.CreateMutableBinding(dn,false)。
        •   
        • 声明:上面对CreateMutableBinding的调用将永远不会返回突然的完成。
        •   
      •   
    10.   
    11. 将运行中的执行上下文的LexicalEnvironment设置为loopEnv。
    12.   
    13. 让forDcl是评估LexicalDeclaration的结果。
    14.   
    15. 如果forDcl是突然完成的,则      
          
      • 将运行中的执行上下文的LexicalEnvironment设置为oldEnv。
      •   
      • 返回完成次数(forDcl)。
      •   
    16.   
    17. 如果isConst为false,则让perIterationLets为boundNames,否则让perIterationLets为«»。
    18.   
    19. 让bodyResult为ForBodyEvaluation(第一个表达式,第二个表达式,语句,perIterationLets,labelSet)。
    20.   
    21. 将运行中的执行上下文的LexicalEnvironment设置为oldEnv。
    22.   
    23. 返回完成(bodyResult)。
    24.   

那为什么为什么在运行以下测试(我从the same question I previously referenced进行测试)时,var的运行速度却比let慢,而不是我所期望的相反呢?

(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

1 个答案:

答案 0 :(得分:1)

我同意@Derek朕会功夫的观点,如果不深入研究实现,就很难推理。

但是,如果使用var,您可能会错过一些步骤:

对于var,实际上执行了 更多 个步骤:

  

IterationStatement:用于(Expressionopt; Expressionopt; Expressionopt)语句

     
      
  1. 如果存在第一个表达式,则      
        
    • 让exprRef为评估第一个表达式的结果。
    •   
    • 让exprValue为 GetValue (exprRef)。
    •   
      •   
      • ReturnIfAbrupt(V)。
      •   
    •   
      •   
      • 如果Type(V)不是Reference,则返回V。
      •   
    •   
      •   
      • 让基为GetBase(V)。
      •   
    •   
      •   
      • 如果IsUnresolvableReference(V),则引发ReferenceError异常。
      •   
    •   
      •   
      • 如果是IsPropertyReference(V),则
      •   
    •   
      •   
        •   
        • 如果HasPrimitiveBase(V)为true,则
        •   
      •   
    •   
      •   
        •   
          •   
          • 声明:在这种情况下,base永远不会为null或未定义。
          •   
        •   
      •   
    •   
      •   
        •   
          •   
          • 让基础成为ToObject(base)。
          •   
        •   
      •   
    •   
      •   
        •   
        • 返回基数。[[Get]](GetReferencedName(V),GetThisValue(V))。
        •   
      •   
    •   
      •   
      • 其他基础必须是环境记录,
      •   
    •   
      •   
        •   
        • 返回base.GetBindingValue(GetReferencedName(V),IsStrictReference(V))(请参阅8.1.1)。
        •   
      •   
    •   
    • ReturnIfAbrupt(exprValue)。
    •   
  2.   
  3. 返回ForBodyEvaluation(第二个表达式,第三个表达式,语句,«»,labelSet)。
  4.   

的其他处理可能来自GetValue