Array.from() 与传播语法
Posted
技术标签:
【中文标题】Array.from() 与传播语法【英文标题】:Array.from() vs spread syntax 【发布时间】:2017-03-25 16:44:54 【问题描述】:使用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()
将记录相同的结果。
有任何性能差异吗?
【问题讨论】:
扩展运算符的好处是它支持Object
。性能.. idk
要了解是否存在任何性能差异,请运行基准测试。根据您是在原生 ES6 环境中还是转译到 ES5,结果可能会大不相同。
主要区别在于Array.from
可用于不实现迭代器协议的类数组对象(即Symbol.iterator
)。即使有了 ES6 和新的浏览器规范,这些规范也越来越少。
...
is not an operator!
【参考方案1】:
如果输入是可迭代的,它们会做完全相同的事情。
但是,根据基准,展开运算符似乎对 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")
【讨论】:
【参考方案2】:我要澄清一下大家的答案:
...foo
语法只是扩展(扩展)所有数组值,就好像它们是单独的逗号分隔的参数一样。它进行了浅层传播。复制任何素数(数字、字符串等),而引用任何复杂值(对象)。
[]
围绕它创建一个新数组。
所以[...foo]
将创建一个新数组并通过对所有数组元素进行 SHALLOW COPY 传播来填充它,就好像它们是数组构造函数参数一样,这反过来又将所有这些复制的元素放入新数组中。李>
而Array.from(foo)
将使用输入变量创建一个新数组,但速度要快得多,因为它只创建一个 SHALLOW COPY(这更快)。所以它需要准确的输入,然后将每个变量/引用放入新数组中。
使用Array.from()
。
【讨论】:
扩展运算符和array.from()
创建浅拷贝都是不正确的。【参考方案3】:
好吧,Array.from
是一个静态方法,即一个函数,而 spread
语法是数组字面量语法的一部分。您可以像数据一样传递函数,您可以调用它们一次、多次或根本不调用它们。这在 spread
语法中是不可能的,在这方面它是静态的。
@nils 已经指出的另一个区别是Array.from
也适用于不实现可迭代协议的类数组对象。另一方面,spread
需要可迭代对象。
【讨论】:
“Array.from 也适用于不实现可迭代协议的类数组对象”——你能举一个这样的对象的例子吗?【参考方案4】:Spread element (it's not an operator) 仅适用于 iterable 的对象(即实现 @@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]
) 时,展开元素很有用。
【讨论】:
虽然我同意Array.from()
是一种非常易读的实现方式,但我认为扩展元素语法 ...arrayLikeObject
对人们来说同样易读(或更多)。
另请注意传播语法 (...arrayLikeObject
) 要短得多。有时这可能是一个因素,但也许不应该如此。
@qarthandso 如果我们扩展到新的(不同的)数组,那么我会同意。但是如果我们需要复制一个数组(复制到完全相同的数组),那么 Array.from 看起来更有吸引力并且至少在某些情况下更具可读性,即当我们需要传递一个起始值 Array.prototype.reduce
来作为数组时,on我们称之为。
警告:var i = 5; Array.from(i)
等数字参数会导致[]
,而var i = 5; [i]
会导致[5]
【参考方案5】:
使用 Babel 是了解内部情况的好方法。
不过,请注意。确保在 Babel 中选择了 latest,因为默认是错误的。
使用上面的示例,这是输出。
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);
【讨论】:
[].concat
如果节点列表不可连接,似乎不起作用?那是 Babel 输出吗?
Is that a Babel output
确实,我只是将代码复制到 babeljs.io,你有例子吗?也许 babel 在需要时会进行其他转换。这当然只是针对这种特定情况进行测试。
babeljs.io repl 有一些奇怪的选项,它不是很可靠。使用[].concat
是不正确的简化(仅与数组参数上的展开语法相同),这可能是由 Babel 中的错误或某些未知设置引起的。
啊,在 babel 中单击 latest
会有所不同。我会用新的输出更新答案.. 感谢您的提醒。
更不用说当您查看 Babel 转译代码时,您没有看到“内部发生了什么”。运行时在内部所做的完全是另外一回事。【参考方案6】:
不同之处在于spread允许数组被扩展。而 from()
创建一个 new 数组。 .from()
不会扩展任何内容,它会根据提供的数据创建一个新数组;另一方面,扩展运算符可以扩展具有新属性的数组。
【讨论】:
好吧,数组字面量也总是创建一个 new 数组…… 我不确定我是否只是误解了你的措辞,但你是否建议扩展运算符改变数组而不是创建一个新数组? @Bergi 以及扩展运算符不会创建 数组。 OP 示例中的数组创建是通过扩展运算符周围的方括号完成的。 啊,好吧,我只是想确定你的意思是对的。如果您说“扩展数组文字”而不是“扩展数组”也许会有所帮助,因为它不会对任意数组进行操作。 澄清一下:...foo
语法只是扩展(扩展)所有数组值,就好像它们是单独的逗号分隔的参数一样。它周围的[]
是创建一个新数组的原因。所以[...foo]
将创建一个新数组并通过将所有数组元素像数组构造函数参数一样展开来填充它,并对每个元素进行完整复制。而Array.from(foo)
将使用输入变量创建一个新数组,并且速度快很多,因为它创建了一个 SHALLOW COPY(这更快)。以上是关于Array.from() 与传播语法的主要内容,如果未能解决你的问题,请参考以下文章