为什么`void 0`可能比“undefined”“更快”?

时间:2016-11-01 10:47:03

标签: javascript performance

只是潜伏在140byte docs的奇怪和奇特的东西,找到了this

  

void 0undefined快,但比替代品更长。

我懒得在Chrome控制台中检查,如下所示:

console.time('void');
for (let a = 0; a < 1e6; a++) {() => void 0};
console.timeEnd('void');

VS

console.time('undefined');
for (let a = 0; a < 1e6; a++) {() => undefined};
console.timeEnd('undefined');

发现没有区别。也许我的懒惰检查太懒了,或者只是关于缓慢的陈述不再相关了。

我只是想知道JS引擎的内部结构以及它是如何实现的?我们怎样才能谈论原语和运算符的速度?它是否正确且相关?这听起来有点奇怪。

1 个答案:

答案 0 :(得分:5)

  

我只是想知道JS引擎的内部结构以及它是如何实现的?我们怎样才能谈论原语和运算符的速度?它是否正确且相关?这听起来有点奇怪。

是的,这是可能的。 undefined是全局变量,而不是关键字。这意味着它可以被遮蔽。因此,为了找到它的值,JavaScript引擎需要遍历作用域链并检查每个作用域级别的"undefined"绑定。例如:

function outer() {
    function middle() {
        function inner() {
            console.log(undefined);
        }
        inner();
    }
    middle();
}
outer();

inner内的引用要求JavaScript引擎检查inner函数的执行上下文的绑定对象,然后检查middle,然后检查outer,最后在全球范围内找到它。

相比之下,voidvoid运算符的关键字,0是文字,因此void 0不需要范围链遍历。由于void运算符定义为始终返回undefined,因此有一种机制可以使其比undefined全局更好地执行。

并不是说它可能很重要。你更有可能做其他会影响你表现的事情。

FWIW,一个天真的基准:

var x = undefined;

var now = performance && performance.now ? performance.now.bind(performance) : Date.now.bind(Date);

function outermost() {
  var a = Math.random();
  function outer() {
    var b = Math.random();
    function inner() {
      var c = Math.random();
      function test1() {
        if (Math.random() > 1) { // Never true
          x = 42;
        }
        return x == undefined;
      }

      function test2() {
        if (Math.random() > 1) { // Never true
          x = 42;
        }
        return x == void 0;
      }

      function test(f, n) {
        var start = now();
        while (n-- > 0) {
          f();
        }
        return now() - start;
      }

      console.log("Testing...");
      setTimeout(function() {
        test(test1, 100000000); // warmup
        test(test2, 100000000); // warmup
        console.log("undefined", test(test1, 1000000000), "ms");
        console.log("void 0   ", test(test2, 1000000000), "ms");
      }, 40);

      if (a + b + c > Infinity) {
        console.log("Impossible, just making sure to use a, b, and c");
      }
    }
    inner();
  }
  outer();
}
outermost();
WARNING: THIS MAY LOCK UP YOUR BROWSER WINDOW.
For me, it runs fine on recent Chrome, taking about 20 seconds; YMMV.