JS数组的shift、splice、slice和解构赋值的区别

3

哪种方法可以更好地提高在 JavaScript 中删除数组的第一个元素的性能?

假设我们有以下数组:

let fruits = ['Apple', 'Orange', 'Banana', 'Lemon'];

1. 移位方法

let a = fruits.shift();

2. splice方法

let [b] = fruits.splice(0, 1);

3. 切片方法

let c;
[c, fruits] = [...fruits.slice(0, 1), fruits.slice(1)]

4. 解构方法

let d;
[d, ...fruits] = fruits;

请说明其中一种方法比另一种更快的原因。
我在jsbench.meperf.link进行了一些测试,但我多次运行了完全相同的测试,并且每次都得到完全相反的结果。
我知道这些事情在不同的环境和引擎中是不同的,所以我想知道哪一个在Chrome V8引擎中更好。

@evolutionxbox 好的,我会这样做,但我认为像jsbench这样的网站在幕后做了完全相同的事情。但实际上我正在寻找更可靠的文档或类似的东西。无论如何,谢谢;) - Davood Taheri
性能差异的文档? - evolutionxbox
@evolutionxbox 不是像文档一样的文档。就像在SEO中发生的那样,有些事情是由Google解释的,我们可以信任,或者是由正在开发V8引擎的人说的一些话,我们可以考虑。你知道比console.time或jsbench更可靠的东西。现在,我不知道是否有这样的东西,但我正在搜索。 - Davood Taheri
1
你能展示一下你所做的测试吗?很有可能你犯了一些微基准错误。 - Bergi
@DavoodTaheri 不行。你应该在实际的应用程序中对你的实际代码进行基准测试。只有这样,引擎才会应用(或不应用)真正重要的优化。 - Bergi
显示剩余8条评论
1个回答

2
根据我的经验,.shift()方法是最容易使用的。但如果你想知道确切的代码速度,我用performance.now()测试了每种方法。
大多数情况下,.shift()方法是最快的。你可能会问为什么?因为它不会重新声明任何变量,而其他方法会重新定义。只有一个变量,调用.shift()方法时自动返回该变量。特别是最后两个例子最慢。它们正在重新定义两个变量,一个变量被分配了两次(c, d)。一次是用let,另一次是在声明时。
这是我用于测试的代码,请随意编辑。

    function speedTest(times) {
    let shiftAvg = 0;
    let spliceAvg = 0;
    let sliceAvg = 0;
    let destructuringAvg = 0;
    let t0, t1;
    let fruits = Array(10000).fill('test');
    for (var i = 0; i < times; i++) {

        t0 = performance.now();
    
        let a = fruits.shift();
    
        t1 = performance.now();

        shiftAvg += t1 - t0;
    
        resetFruits();
        
        t0 = performance.now();
    
        let [b] = fruits.splice(0, 1);
    
        t1 = performance.now();
        spliceAvg += t1 - t0;
    
        resetFruits();
        
        t0 = performance.now();
    
        let c;
        [c, fruits] = [...fruits.slice(0, 1), fruits.slice(1)];
    
        t1 = performance.now();
        sliceAvg += t1 - t0;
    
        resetFruits();
        
        t0 = performance.now();
    
        let d;
        [d, ...fruits] = fruits;
    
        t1 = performance.now();
        destructuringAvg += t1 - t0;
    
        resetFruits();
    }
    
    shiftAvg = shiftAvg / times;
    spliceAvg = spliceAvg / times;
    sliceAvg = sliceAvg / times;
    destructuringAvg = destructuringAvg / times;

    return [
        {"avg": destructuringAvg, "approach": 'destructuring'},
        {"avg": spliceAvg, "approach": 'splice'},
        {"avg": sliceAvg, "approach": 'slice'},
        {"avg": shiftAvg, "approach": 'shift'}
    ];
    
    function resetFruits() {
        fruits = Array(10000).fill('test');
    }
}

let result = speedTest(20000).sort((a, b) => (a.avg > b.avg) ? 1 : -1);

result.map((item, index, self) => {
    if(index === 0) {
        console.log(index + 1, item.approach, item.avg, `fastest`);
    }
    else {
        console.log(index + 1, item.approach, item.avg, `${parseInt(item.avg / self[0].avg * 100 - 100)}% slower`);
    }
    
});

此外,不仅代码执行速度快,而且键入array.slice()比键入整个解构代码要快。

希望我能帮助你 :)


1
我运行了这个示例,除了1/slice之外的所有输出都是“0.000ms”。 - evolutionxbox
是的,就像我说的那样,在 HTML 文档中的 JS 代码中尝试自己运行它。Stack Overflow 并没有显示正确的结果。 - RedCrafter07
1
但这清楚地表明,所有这些方法都非常快。 - RedCrafter07
1
即使在新标签页中运行,我得到的所有结果都是0ms。我认为差异很可能如此之小,以至于可以忽略不计。 - evolutionxbox
那很可能是正确的。我在与HTML文档相关联的js文件中运行它,结果非常准确。shift()通常是最快的。 - RedCrafter07

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