Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

copyWithinを使った高速shift

配列操作でのshiftはコストが高いことで有名です。ところでつい先日ES2015にcopyWithinというメソッドが追加されていたことを知りました(今更)。調べてみたところ「左詰め」のようにズラす操作が得意なようです。これはshiftに使えるのではないか、と思い検証してみました。

検証

検証にはjsPerfを使用しました。fast shiftが今回つくった関数、native shiftが配列のshiftメソッドです。(500)とあるものは500個左へ詰める操作をしたときです。

fast shift · jsPerf

Browserfast shiftnative shiftfast shift(500)native shift(500)
Chrome 60.0.3112 1,646±8.20% 17% slower 1,990±8.18% 2,188±9.71% 1,685±6.45% 21% slower
Edge 13.10586.0 1,401±3.93% 14% slower 1,622±3.91% 1,499±4.67% 1,073±2.31% 27% slower
Mobile Safari 11.0.0 5,646±8.47% 66% slower 15,479±1.34% 8,585±0.90% 5,681±1.05% 34% slower
Chrome Mobile iOS 62.0.3202 5,800±3.93% 63% slower 15,380±1.57% 8,271±2.02% 5,715±0.51% 30% slower

きれいな結果が出ました。

考察

1つだけズラす場合はネイティブのshiftメソッド、500個ズラす場合はcopyWithinを使った関数のほうが早いという結果になりました。

つまり、適当なしきい値を決めて、それ以下ならネイティブ、それより上ならcopyWithin版を使うようにすればいいということです。

ということでこれが高速化されたshiftです。

const fastShift = (arr, n) => {
    if (n > 100) {
        const res = arr.slice(0, n);
        arr.copyWithin(0, n);
        arr.length -= n;
        return res;
    }
    const res = [];
    for (let i = 0, _i = arr.length; i < _i; i = 0 | i + 1) {
        res[i] = arr.shift();
    }
    return res;
}

イマイチ用途の判然としないcopyWithinですが、左詰めする場面なら使い道があるよ、という話でした。もっとも、複数個をまとめて左詰めしたくなる場面なんてそうない気がしますが。