为什么检查 void 0 比检查 undefined 快得多?

3

在使用gulp-uglify压缩JavaScript文件之后,我注意到了一些有趣的问题。我传递undefined到全局IIFE包装器中,我看到它被改成了void 0。什么是void 0?我在控制台上运行它并返回undefined,这很有趣!这让我很好奇,所以我开始对void 0进行测试。在我的控制台测试中(简单的循环和时间戳),我观察到使用void 0而不是undefined可以提高180倍的速度,具体取决于浏览器。是否有人知道为什么检查void 0会更快?

(function(start, x, z){
    for (var i=0; i<z; i++){
      if (x === undefined){}
    }
    console.info('t1 ', Date.now() - start);
    start = Date.now();
    for (var i=0; i<z; i++){
      if (x === void 0){}
    }
    console.info('t1 ', Date.now() - start);
})(Date.now(), '', 1e6)

1
不,void 0 是一个原始值,undefined 是一个全局变量。 - ewramner
1
value undefined 是一个原始值,但是当使用标识符时,它通过全局变量进行访问。 - user8897421
1
总的来说,对微基准测试要持怀疑态度。它们很难做到正确。单个测试不应该太具有说服力。我认为大多数实现都可以静态确定全局的 undefined 没有被遮蔽,因此可以优化作用域链遍历。 - user8897421
1
@user2612030: void 0 是一个表达式(使用 void 运算符),它返回原始值 undefined,就像 SterlingArcher 所写的一样。 - user8897421
1
@Pointy,你错了:首先是指针,void关键字在其后运行表达式,所以for循环做了一些事情:每次迭代都会运行0!其次,我尝试使用创建和删除DOM元素的相同代码来执行更多操作。这里是fiddle - Davide Cannizzo
显示剩余6条评论
1个回答

2
实际上,我刚意识到void 0和undefined之间的区别。undefined是全局范围内的值,而void是一个运算符。在这个测试中发生的是,全局范围内正在检查未定义的内容,而void 0则不需要在检查其值时进行范围遍历,因为它是一个使用运算符void的表达式。如果将undefined传递给IIFE包装器,则测试结果将相同。原始测试显示的性能差异实际上只测量了1e6次范围遍历的时间成本。
进一步证明代码表明这是正确的。下面的for循环具有相同的执行时间:
(function(start, x, z, undefined, c, Math){
    for (var i=0; i<z; i++){
    if (x !== undefined){
        c = Math.random();
    }
    }
    console.info('t1 ', Date.now() - start);
    start = Date.now();
    c = 0;
    for (var i=0; i<z; i++){
        if (x !== void 0){
            c = Math.random();
        }
    }
    console.info('t1 ', Date.now() - start);
})(Date.now(), '', 1e6, undefined, 0, Math)

Rock Star提出了一个很好的观点,即结果取决于代码的编写方式,例如内存中是否访问了有条件的分配值。根据我的测试,如果您将这些值作为参数传递给函数,结果会有很大的差异。此时,浏览器可能会决定做更少的优化。尽管如此,在我进行的每个测试中,void 0仍然比undefined更快或等效,使用的kb更少,并且它消除了对遍历范围的担忧。


2
原始测试中显示的性能差异实际上只是测量了范围遍历1e6次的时间成本。那么循环本身呢?如何进行优化?需要多少次通过,以什么顺序进行?也许使用void 0,它们的优化可以让它们早期消除if语句,从而消除整个循环,但是使用undefined时,if被消除,但在稍后的通过中,因此循环本身仍然存在。或者使用undefinedif保留,但范围遍历被消除,因此循环和===比较仍然存在。 - user8897421
将某些内容放在“if”块中为什么会改变任何东西?如果“if”总是“false”,则其中的代码永远不会运行。而声明该循环在任何意义上都没有被优化是相当愚蠢的。您不知道正在发生什么优化以及它们可能发生的条件。除非您告诉我您已经研究了要测试的实现的源代码,否则就不要告诉我。 - user8897421
“证明 if 循环没有被浏览器秘密优化” 不,你没有仔细阅读我的评论,关于多个优化通道的可能性以及它们相互之间的时间关系。也许与全局变量相关的任何优化都发生在最后,以便它们可以确保它们不会被更改或遮蔽。面对现代优化编译器的巨大复杂性,你假设得太多了。 - user8897421
所以不要对性能做出如此死板的结论,因为你和我们大多数人都不知道。顺便说一下,你还没有回答你是否在控制台中进行测试。如果是这样,那就是另一个大错误。 - user8897421
既然你没有删除这个错误的答案,我会添加一个更好的性能测试来展示实际上几乎没有区别,以免误导其他人。https://jsfiddle.net/nv0pjch8/ 它强制循环填充一个包含Math.random()值的数组,然后在随机索引处打印循环中的一个值。这样,编译器就无法知道哪一个将被选择,因此它不能消除任何一个。 - user8897421
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接