一.前言
邓黄海在2018年V8团队实习时,他致力于提升了[...array]、[...string]、[...set]、[...map.keys()]和[...map.values()]的性能。他甚至使得Array.from(iterable)更快了。
关于本文分享的他的魔改细节,你可以大胆食用!因为这些优化从 V87.2版本就已经带上了。你也不需要过度担心你的代码,特别是使用...的代码。
额外插一句,邓黄海是越南人,不是中国人嗷。他博士毕业于 MPI-SWS。在当时他使用 V8 的内部语言CodeStubAssembler (CSA) 优化 JavaScript 代码。CSA 是一种基于 C++ 的类似汇编的 goto 语言,可为 Chrome 支持每种架构并生成汇编代码。
二.扩展元素
...操作符英文名称是Spreadsyntax,译为扩展语法(展开语法)。它只能对iterableObj进行操作。iterableObj会提供一个迭代器,即可通过[Symbol.iterator]()进行访问。
所以,扩展元素的定义是 使用了...的元素,即形如...iterableObj。
它在 ES2015 中作为一种从iterable objects中创建数组的方式而被引入。例如:
const a = [2, 3];
const b = [5, 6, 7];
const result = [1, ...a, 4, ...b];
// → [1, 2, 3, 4, 5, 6, 7]
const str = '阿吉的公众号';
const result = [...str];
// → ['阿', '吉', '的', '公', '众', '号']
const s = new Set();
s.add('V8');
s.add('TurboFan');
const result = [...s];
// → ['V8', 'TurboFan']
举个简单例子,浅克隆一个数组arr,在ES6中我们常用[...arr]。
很不幸,这种惯用方式的性能远远落后于它的 ES5 对应物,即用ES5自定义一个浅克隆数组方法。
但当前你可以放心,邓黄海实习时致力于解决这个问题,当前已经解决。
三.为何曾经扩展元素很慢
有很多方法可以对数组进行浅克隆,比如arr.slice()、arr.concat()、[...arr],甚至可以用for循环自定义一个clone方法。如下:
function clone(arr) {
// Pre-allocate the correct number of elements, to avoid
// having to grow the array.
const result = new Array(arr.length);
for (let i = 0; i < arr.length; i++) {
result[i] = arr[i];
return result;
理想情况下,上述提及的几种方式,性能应该大致相近。
但很不幸,在v7.2之前,[...arr]会比自定义的clone都慢。因为本质上V8会把[...arr]转换成如下:
function(arr) {
const result = [];
const iterator = arr[Symbol.iterator]();
const next = iterator.next;
for ( ; ; ) {
const iteratorResult = next.call(iterator);
if (ite