为什么存在 Array.of?

huangapple go评论92阅读模式
英文:

Why does Array.of exist?

问题

为什么存在Array.of?据我所知,它只是从传递的参数创建一个数组(例如Array.of(1,2,3) -> [1,2,3])。

这个JSPerf显示,这个简单的替代函数(它的工作方式完全相同)比Array.of 快80-90%。

const array_of = (...args) => [...args];

^ 这是有效的ES6语法,Array.of也是如此。

英文:

Why does Array.of exist? AFAIK it simply creates an array from the arguments passed (i.e Array.of(1,2,3) -> [1,2,3]).

This JSPerf shows that this simple replacement function (which works exactly the same way) performs 80-90% faster than Array.of

const array_of = (...args) => [...args];

^ this is valid ES6 and so is Array.of

答案1

得分: 2

这完全没问题。向函数传递大量参数并创建其堆栈帧只是一项昂贵的操作。

此外,如果您参考文档,它是Array的静态方法:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of

因此,还有其他情景可以使用它,例如子类化Array,这样您可以创建您的Array子类的实例。这可能很有用,例如将其作为对您的子类的工厂的引用传递。

虽然在通常用于Web应用程序中的数据大小上性能较差,但这可能并不重要。

英文:

That's totally OK. Passing a lot of parameters to a function and creating its stack frame is just an expensive operation.

Also if you refer to the documentation, it's a static method of Array:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of

So there're additional scenarios how to use it, like subclassing Array so you can create instances of your subclass of Array. That could be useful, like passing it by reference as a factory for your subclass.

While its less performant that could be not important on usual data sizes used in web app.

答案2

得分: 2

我还可以说,这是因为Array.of可以在不支持扩展运算符的旧浏览器中使用。它是**ECMAScript 6(ES6)**的一部分,是内置对象。它与其他内置方法(例如Array.fromArray.map)更一致。

其主要原因是提供比传统的Array构造函数更可预测的构造函数

这意味着当你创建Array(3)时,它创建一个长度为3的空数组,而不是一个只包含一个元素3的数组。而在Array.of的情况下,它始终根据传递给它的参数创建数组,这有助于避免产生意外的结果。

英文:

I can also say that it is because of Array.of can be used in older browsers that do not support the spread operator. It is the part of ECMAScript 6 (ES6) as built-in object. It is more consistent with other built-in methods, such as Array.from and Array.map.

> The main reason for, it is to provide more predictable constructor than the traditional Array constructor.

This above means that when you create Array(3) it creates an empty array length 3, not an array with single element, 3. In case of Array.of It always creates an array with the arguments you pass to it. which is good to not making unexpected results.

答案3

得分: 1

公平的问题。我将尝试给出公平的回答。

我的观点是

const arr = Array.of(...args);

const arr = (...args) => [...args];

更清晰。

为什么?

在这两种情况下,我们都在创建一个新数组。这很关键,因为数组是按引用处理的。长话短说:我们都同意下面的代码将更新两个数组:

const x = [1, 2, 3];
const y = x;

y.push(4);

console.log(x, y);

xy 数组现在都有4个元素,因为y只是对已创建的x数组的引用。对y的任何修改都将影响由xy引用的实例。

这就是为什么当我们克隆复杂类型(而不是原始类型)时,我们希望新实例是分离的,不会影响原始值。在我们的示例中,我们将进行以下修改以获得更期望的结果:

const x = [1, 2, 3];
const y = Array.of(...x);

y.push(4);

console.log(x, y);

很明显yx的克隆,对我来说至少比以下方式更清晰:

const x = [1, 2, 3];
const y = (...args) => [...args]; // 同样的效果,但我们确定我们理解发生了什么吗?

y.push(4);

console.log(x, y);

我的问题是: 为什么要止步于此?如果我们需要克隆一个对象呢?

虽然有些人认为这是一个很酷的方法:

const x = { hello: 'world' };

const y = { ...x };

但我认为经典的方式更可读:

const x = { hello: 'world' };

const y = Object.assign({}, x);

你不必成为JavaScript大师才能理解它。

另外,值得一提的是,对于这两种情况,你都可以使用以下方式来克隆:

const x = { something: 'else', with: [{ 'way': 'more' }, levels: [1, 2, 3]] };

const y = JSON.parse(JSON.stringify(x));

这是一种非常简单的方法(或者说是一种不太正规的方法),用于序列化和反序列化一个对象,创建其完美的克隆。

总之:

当性能很重要时,团队的表现也至关重要。他们很可能会理解并且更欣赏性能更好的代码(并且可能会对遇到 forEach 循环时感到不满)。

在其他情况下,保持代码简单,以便其他人可以维护你的代码库。

干杯!

英文:

Fair question. I will try to give it a fair answer

My argument is that

const arr = Array.of(...args);

Is more clear than

const arr = (...args) => [...args];

Why?

In both cases we are creating a new array. This is crucial because arrays are handled by reference. Long story short: we all agree that the below code will update both arrays

const x = [ 1, 2, 3 ];
const y = x;

y.push(4);

console.log(x, y);

Both x and y arrays has now 4 elements, because y is only a reference to the already created x array. Any modification in y will address the instance referenced by both x and y

That is why, when we are cloning complex types (not primitives) we intend the new instance to be separated and not affect the original value. In our example, will will make the following modification to get more excepted results

const x = [ 1, 2, 3 ];
const y = Array.of(...x);

y.push(4);

console.log(x, y);

It is clear that y is a clone of x, for me at least, way more than just

const x = [ 1, 2, 3 ];
const y = (...args) => [...args]; // smae effect, still - are we sure we understand what's going on?

y.push(4);

console.log(x, y);

My question is: why stopping here? What if we need to clone an object instead?

While some argue that this is a cool way to do it

const x = { hello: 'world' };

const y = { ...food };

I think that the classic way is more readable

const x = { hello: 'world' };

const y = Object.assign({}, x);

You don't have to be javascript master in order to understand it

Also, it worth mentioning that for both cases you can make a clone by using

const x = { something: 'else', with: [ { 'way': 'more' }, levels: [ 1, 2, 3 ] ] };

const y = JSON.parse(JSON.stringify(x));

Which is a very simple way (or a dirty hack) to serialize and desterilize an object, creating a perfect clone of it

In conclusion:

When performance matters, the performance of the team is crucial as well. Most chances that they will understand and also appreciate more performant code (and will probably be bitter whenever they encounter forEach loop)

In any other case, keep it simple for other humans to maintain your code base

Cheers

huangapple
  • 本文由 发表于 2023年6月29日 01:09:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76575350.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定