Array.from() 与传播语法

IT技术 javascript arrays ecmascript-6
2021-03-22 19:03:31

使用Array.from(document.querySelectorAll('div'))之间有什么区别[...document.querySelectorAll('div')]吗?

下面是一个例子:

let spreadDivArray = [...document.querySelectorAll('div')];
console.log(spreadDivArray);

let divArrayFrom = Array.from(document.querySelectorAll('div'));
console.log(divArrayFrom);

console.log()将记录相同的结果。

有什么性能差异吗?

6个回答

Spread元素它不是运算符)仅适用于可迭代的对象(即实现该@@iterator方法)。Array.from()也适用于length不可迭代的类数组对象(即具有属性和索引元素的对象)。看这个例子:

const arrayLikeObject = { 0: 'a', 1: 'b', length: 2 };

// This logs ['a', 'b']
console.log(Array.from(arrayLikeObject));
// This throws TypeError: arrayLikeObject[Symbol.iterator] is not a function
console.log([...arrayLikeObject]);

另外,如果您只想将某些内容转换为数组,我认为最好使用Array.from()因为它更具可读性。例如,当您想要连接多个数组 ( ['a', 'b', ...someArray, ...someOtherArray])时,展开元素很有用

另请注意,展开语法 ( ...arrayLikeObject) 要短得多。有时这可能是一个因素,但也许不应该是。
2021-05-05 19:03:31
虽然我同意这Array.from()是一种非常易读的实现方式,但我觉得传播元素语法...arrayLikeObject对人们来说同样可读(或更多)。
2021-05-09 19:03:31
警告:number 参数,例如var i = 5; Array.from(i)results in []where as var i = 5; [i]results in[5]
2021-05-11 19:03:31
@qarthandso 如果我们正在扩展到新的(不同的)数组,那么我会同意。但是如果我们需要复制一个数组(成完全相同的一个),那么 Array.from 看起来更有吸引力,至少在某些情况下更具可读性,即当我们需要传递一个Array.prototype.reduce作为数组的起始值时,我们调用它。
2021-05-16 19:03:31

嗯,Array.from是一个静态方法,即一个函数,而spread语法是数组文字语法的一部分。您可以像数据一样传递函数,可以调用一次、多次或根本不调用它们。这对于spread语法来说是不可能的,在这方面它是静态的。

@nils 已经指出的另一个区别是,它Array.from也适用于不实现可迭代协议的类数组对象。spread另一方面需要迭代。

“Array.from 也适用于类似数组的对象,它没有实现可迭代协议”——你能举一个这样的对象的例子吗?
2021-04-30 19:03:31

不同之处在于 spread 允许扩展数组from()创建一个数组。.from()不扩展任何东西,它根据提供的数据创建一个新数组;另一方面,扩展运算符可以扩展具有新属性的数组。

@Bergi 好,展开运算符不会创建数组。OP 示例中的数组创建是通过展开运算符周围的方括号完成的。
2021-04-27 19:03:31
啊,好的,我只是想确定你的意思是正确的。如果您说“扩展数组文字”而不是“扩展数组”可能会有所帮助,因为它不会对任意数组进行操作。
2021-04-30 19:03:31
好吧,数组字面量也总是会创建一个数组……
2021-05-08 19:03:31
澄清:...foo语法刚涂抹酱(膨胀)的所有数组值,就好像它们是分开的,用逗号分隔的参数。[]周围是创建一个新数组的东西。So[...foo]将创建一个新数组并通过传播所有数组元素来填充它,就好像它们是数组构造函数参数一样,并对每个元素进行完整复制。Array.from(foo)将使用输入变量创建一个新数组,并且速度更快,因为它创建了一个浅拷贝(这更快)。
2021-05-08 19:03:31
我不确定我是否只是误解了您的措辞,但是您是在建议扩展运算符会改变数组而不是创建一个新数组吗?
2021-05-14 19:03:31

如果输入是可迭代的,它们会做完全相同的事情。

然而,根据基准,价差算子似乎对 Set 表现更好。

https://jsben.ch/5lKjg

let set = new Set();
for (let i = 0; i < 10000; i++) {
  set.add(Math.random());
}


let tArrayFrom = window.performance.now()

let arr = Array.from(set)

console.log("Array.from():", window.performance.now() - tArrayFrom + "ms")


// slightly faster in most of the runs:
let tSpread = window.performance.now()

let arr2 = [...set];

console.log("Spread syntax:", window.performance.now() - tSpread + "ms")

使用 Babel 是查看内部发生的事情的好方法。

不过,请抬头。确保在 Babel 中选择了最新的,因为默认是错误的。

使用上面的示例,这是输出。

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

var spreadDivArray = [].concat(_toConsumableArray(document.querySelectorAll('div')));
console.log(spreadDivArray);

var divArrayFrom = Array.from(document.querySelectorAll('div'));
console.log(divArrayFrom);
babeljs.io repl 有一些奇怪的选项,它不是很可靠。使用[].concat是一种不正确的简化(仅与数组参数的扩展语法相同),这可能是由 Babel 中的错误或某些未知设置引起的。
2021-05-04 19:03:31
更何况,你看“什么内部发生”当你看到巴贝尔transpiled代码。运行时在内部所做的完全是另一回事。
2021-05-12 19:03:31
Is that a Babel output确实,我只是将代码复制到 babeljs.io,你有例子吗?,也许 babel 在需要时会做其他转换。这当然只是针对这种特定情况进行测试。
2021-05-16 19:03:31
啊,点击latestbabel 会有所不同.. 我会用新的输出更新答案.. 感谢您的提醒。
2021-05-18 19:03:31
[].concat如果节点列表不可读,似乎不起作用?那是 Babel 输出吗?
2021-05-20 19:03:31