Skip to content

Commit 21efc53

Browse files
committed
Reference for stage 4 change-array-by-copy
1 parent 2e8df2b commit 21efc53

File tree

15 files changed

+651
-22
lines changed

15 files changed

+651
-22
lines changed

files/en-us/web/javascript/reference/global_objects/array/@@species/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ browser-compat: javascript.builtins.Array.@@species
99

1010
The **`Array[@@species]`** static accessor property returns the constructor used to construct return values from array methods.
1111

12-
> **Warning:** The existence of `@@species` allows execution of arbitrary code and may create security vulnerabilities. It also makes certain optimizations much harder. Engine implementers are [investigating whether to remove this feature](https://github.com/tc39/proposal-rm-builtin-subclassing). Avoid relying on it if possible.
12+
> **Warning:** The existence of `@@species` allows execution of arbitrary code and may create security vulnerabilities. It also makes certain optimizations much harder. Engine implementers are [investigating whether to remove this feature](https://github.com/tc39/proposal-rm-builtin-subclassing). Avoid relying on it if possible. New array methods, such as {{jsxref("Array/toReversed", "toReversed()")}}, do not use `@@species` and always return a new `Array` base class instance.
1313
1414
## Syntax
1515

files/en-us/web/javascript/reference/global_objects/array/@@unscopables/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ The default `Array` properties that are ignored for `with` statement-binding pur
3131
- [`flatMap()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap)
3232
- [`includes()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes)
3333
- [`keys()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys)
34+
- [`toReversed()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toReversed)
35+
- [`toSorted()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted)
36+
- [`toSpliced()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSpliced)
3437
- [`values()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values)
3538

3639
`Array.prototype[@@unscopables]` is an empty object only containing all the above property names with the value `true`. Its [prototype is `null`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects), so `Object.prototype` properties like [`toString`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString) won't accidentally be made unscopable, and a `toString()` within the `with` statement will continue to be called on the array.

files/en-us/web/javascript/reference/global_objects/array/index.md

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,14 @@ These methods treat empty slots as if they are `undefined`:
125125

126126
### Copying methods and mutating methods
127127

128-
Some methods do not mutate the existing array that the method was called on, but instead return a new array. They do so by first accessing [`this.constructor[Symbol.species]`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/@@species) to determine the constructor to use for the new array. The newly constructed array is then populated with elements. The copy always happens [_shallowly_](/en-US/docs/Glossary/Shallow_copy) — the method never copies anything beyond the initially created array. Elements of the original array(s) are copied into the new array as follows:
128+
Some methods do not mutate the existing array that the method was called on, but instead return a new array. They do so by first constructing a new array and then populating it with elements. The copy always happens [_shallowly_](/en-US/docs/Glossary/Shallow_copy) — the method never copies anything beyond the initially created array. Elements of the original array(s) are copied into the new array as follows:
129129

130130
- Objects: the object reference is copied into the new array. Both the original and new array refer to the same object. That is, if a referenced object is modified, the changes are visible to both the new and original arrays.
131131
- Primitive types such as strings, numbers and booleans (not {{jsxref("Global_Objects/String", "String")}}, {{jsxref("Global_Objects/Number", "Number")}}, and {{jsxref("Global_Objects/Boolean", "Boolean")}} objects): their values are copied into the new array.
132132

133133
Other methods mutate the array that the method was called on, in which case their return value differs depending on the method: sometimes a reference to the same array, sometimes the length of the new array.
134134

135-
The following methods create new arrays with `@@species`:
135+
The following methods create new arrays by accessing [`this.constructor[Symbol.species]`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/@@species) to determine the constructor to use:
136136

137137
- {{jsxref("Array/concat", "concat()")}}
138138
- {{jsxref("Array/filter", "filter()")}}
@@ -142,19 +142,36 @@ The following methods create new arrays with `@@species`:
142142
- {{jsxref("Array/slice", "slice()")}}
143143
- {{jsxref("Array/splice", "splice()")}} (to construct the array of removed elements that's returned)
144144

145-
Note that {{jsxref("Array/group", "group()")}} and {{jsxref("Array/groupToMap", "groupToMap()")}} do not use `@@species` to create new arrays for each group entry, but always use the plain `Array` constructor. Conceptually, they are not copying methods either.
145+
The following methods always create new arrays with the `Array` base constructor:
146146

147-
The following methods mutate the original array:
147+
- {{jsxref("Array/toReversed", "toReversed()")}}
148+
- {{jsxref("Array/toSorted", "toSorted()")}}
149+
- {{jsxref("Array/toSpliced", "toSpliced()")}}
150+
- {{jsxref("Array/with", "with()")}}
148151

149-
- {{jsxref("Array/copyWithin", "copyWithin()")}}
150-
- {{jsxref("Array/fill", "fill()")}}
151-
- {{jsxref("Array/pop", "pop()")}}
152-
- {{jsxref("Array/push", "push()")}}
153-
- {{jsxref("Array/reverse", "reverse()")}}
154-
- {{jsxref("Array/shift", "shift()")}}
155-
- {{jsxref("Array/sort", "sort()")}}
156-
- {{jsxref("Array/splice", "splice()")}}
157-
- {{jsxref("Array/unshift", "unshift()")}}
152+
{{jsxref("Array/group", "group()")}} and {{jsxref("Array/groupToMap", "groupToMap()")}} do not use `@@species` to create new arrays for each group entry, but always use the plain `Array` constructor. Conceptually, they are not copying methods either.
153+
154+
The following table lists the methods that mutate the original array, and the corresponding non-mutating alternative:
155+
156+
| Mutating method | Non-mutating alternative |
157+
| ---------------------------------------------- | ----------------------------------------------------- |
158+
| {{jsxref("Array/copyWithin", "copyWithin()")}} | No one-method alternative |
159+
| {{jsxref("Array/fill", "fill()")}} | No one-method alternative |
160+
| {{jsxref("Array/pop", "pop()")}} | {{jsxref("Array/slice", "slice(0, -1)")}} |
161+
| {{jsxref("Array/push", "push(v1, v2)")}} | {{jsxref("Array/concat", "concat([v1, v2])")}} |
162+
| {{jsxref("Array/reverse", "reverse()")}} | {{jsxref("Array/toReversed", "toReversed()")}} |
163+
| {{jsxref("Array/shift", "shift()")}} | {{jsxref("Array/slice", "slice(1)")}} |
164+
| {{jsxref("Array/sort", "sort()")}} | {{jsxref("Array/toSorted", "toSorted()")}} |
165+
| {{jsxref("Array/splice", "splice()")}} | {{jsxref("Array/toSpliced", "toSpliced()")}} |
166+
| {{jsxref("Array/unshift", "unshift(v1, v2)")}} | {{jsxref("Array/concat", "toSpliced(0, 0, v1, v2)")}} |
167+
168+
An easy way to change a mutating method into a non-mutating alternative is to use the [spread syntax](/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) or {{jsxref("Array/slice", "slice()")}} to create a copy first:
169+
170+
```js-nolint
171+
arr.copyWithin(0, 1, 2); // mutates arr
172+
const arr2 = arr.slice().copyWithin(0, 1, 2); // does not mutate arr
173+
const arr3 = [...arr].copyWithin(0, 1, 2); // does not mutate arr
174+
```
158175

159176
### Iterative methods
160177

@@ -347,12 +364,20 @@ These properties are own properties of each `Array` instance.
347364
- : Adds and/or removes elements from an array.
348365
- {{jsxref("Array.prototype.toLocaleString()")}}
349366
- : Returns a localized string representing the calling array and its elements. Overrides the {{jsxref("Object.prototype.toLocaleString()")}} method.
367+
- {{jsxref("Array.prototype.toReversed()")}}
368+
- : Returns a new array with the elements in reversed order, without modifying the original array.
369+
- {{jsxref("Array.prototype.toSorted()")}}
370+
- : Returns a new array with the elements sorted in ascending order, without modifying the original array.
371+
- {{jsxref("Array.prototype.toSpliced()")}}
372+
- : Returns a new array with some elements removed and/or replaced at a given index, without modifying the original array.
350373
- {{jsxref("Array.prototype.toString()")}}
351374
- : Returns a string representing the calling array and its elements. Overrides the {{jsxref("Object.prototype.toString()")}} method.
352375
- {{jsxref("Array.prototype.unshift()")}}
353376
- : Adds one or more elements to the front of an array, and returns the new `length` of the array.
354377
- {{jsxref("Array.prototype.values()")}}
355378
- : Returns a new [_array iterator_](/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators) object that contains the values for each index in the array.
379+
- {{jsxref("Array.prototype.with()")}}
380+
- : Returns a new array with the element at the given index replaced with the given value, without modifying the original array.
356381
- [`Array.prototype[@@iterator]()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/@@iterator)
357382
- : An alias for the [`values()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values) method by default.
358383

files/en-us/web/javascript/reference/global_objects/array/reverse/index.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ browser-compat: javascript.builtins.Array.reverse
99

1010
The **`reverse()`** method reverses an array _[in place](https://en.wikipedia.org/wiki/In-place_algorithm)_ and returns the reference to the same array, the first array element now becoming the last, and the last array element becoming the first. In other words, elements order in the array will be turned towards the direction opposite to that previously stated.
1111

12+
To reverse the elements in an array without mutating the original array, use {{jsxref("Array/toReversed", "toReversed()")}}.
13+
1214
{{EmbedInteractiveExample("pages/js/array-reverse.html")}}
1315

1416
## Syntax
@@ -58,7 +60,7 @@ reversed[0] = 5;
5860
console.log(numbers[0]); // 5
5961
```
6062

61-
In case you want `reverse()` to not mutate the original array, but return a [shallow-copied](/en-US/docs/Glossary/Shallow_copy) array like other array methods (e.g. [`map()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)) do, you can do a shallow copy before calling `reverse()`, using the [spread syntax](/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) or [`Array.from()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from).
63+
In case you want `reverse()` to not mutate the original array, but return a [shallow-copied](/en-US/docs/Glossary/Shallow_copy) array like other array methods (e.g. [`map()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)) do, use the {{jsxref("Array/toReversed", "toReversed()")}} method. Alternatively, you can do a shallow copy before calling `reverse()`, using the [spread syntax](/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) or [`Array.from()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from).
6264

6365
```js
6466
const numbers = [3, 2, 4, 1, 5];
@@ -104,4 +106,5 @@ console.log(Array.prototype.reverse.call(arrayLike));
104106

105107
- {{jsxref("Array.prototype.join()")}}
106108
- {{jsxref("Array.prototype.sort()")}}
109+
- {{jsxref("Array.prototype.toReversed()")}}
107110
- {{jsxref("TypedArray.prototype.reverse()")}}

files/en-us/web/javascript/reference/global_objects/array/sort/index.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ The **`sort()`** method sorts the elements of an array _[in place](https://en.wi
1212
The time and space complexity of the sort cannot be guaranteed as it depends on the
1313
implementation.
1414

15+
To sort the elements in an array without mutating the original array, use {{jsxref("Array/toSorted", "toSorted()")}}.
16+
1517
{{EmbedInteractiveExample("pages/js/array-sort.html")}}
1618

1719
## Syntax
@@ -240,7 +242,7 @@ sorted[0] = 10;
240242
console.log(numbers[0]); // 10
241243
```
242244

243-
In case you want `sort()` to not mutate the original array, but return a [shallow-copied](/en-US/docs/Glossary/Shallow_copy) array like other array methods (e.g. [`map()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)) do, you can do a shallow copy before calling `sort()`, using the [spread syntax](/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) or [`Array.from()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from).
245+
In case you want `sort()` to not mutate the original array, but return a [shallow-copied](/en-US/docs/Glossary/Shallow_copy) array like other array methods (e.g. [`map()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)) do, use the {{jsxref("Array/toSorted", "toSorted()")}} method. Alternatively, you can do a shallow copy before calling `sort()`, using the [spread syntax](/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) or [`Array.from()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from).
244246

245247
```js
246248
const numbers = [3, 1, 4, 1, 5];
@@ -357,6 +359,7 @@ console.log(Array.prototype.sort.call(arrayLike));
357359

358360
- [Polyfill of `Array.prototype.sort` with modern behavior like stable sort in `core-js`](https://github.com/zloirock/core-js#ecmascript-array)
359361
- {{jsxref("Array.prototype.reverse()")}}
362+
- {{jsxref("Array.prototype.toSorted()")}}
360363
- {{jsxref("String.prototype.localeCompare()")}}
361364
- [About the stability of the algorithm used by V8 engine](https://v8.dev/blog/array-sort)
362365
- [V8 sort stability](https://v8.dev/features/stable-sort)

files/en-us/web/javascript/reference/global_objects/array/splice/index.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ browser-compat: javascript.builtins.Array.splice
88
{{JSRef}}
99

1010
The **`splice()`** method changes the contents of an array by
11-
removing or replacing existing elements and/or adding new elements [in place](https://en.wikipedia.org/wiki/In-place_algorithm). To access part of an array without modifying it, see {{jsxref("Array.prototype.slice()", "slice()")}}.
11+
removing or replacing existing elements and/or adding new elements [in place](https://en.wikipedia.org/wiki/In-place_algorithm).
12+
13+
To create a new array with a segment removed and/or replaced without mutating the original array, use {{jsxref("Array/toSpliced", "toSpliced()")}}. To access part of an array without modifying it, see {{jsxref("Array.prototype.slice()", "slice()")}}.
1214

1315
{{EmbedInteractiveExample("pages/js/array-splice.html")}}
1416

@@ -180,6 +182,7 @@ console.log(arrayLike);
180182

181183
## See also
182184

183-
- {{jsxref("Array.prototype.push()", "push()")}} / {{jsxref("Array.prototype.pop()", "pop()")}}— add/remove elements from the end of the array
184-
- {{jsxref("Array.prototype.unshift()", "unshift()")}} / {{jsxref("Array.prototype.shift()", "shift()")}}— add/remove elements from the beginning of the array
185-
- {{jsxref("Array.prototype.concat()", "concat()")}}— returns a new array comprised of this array joined with other array(s) and/or value(s)
185+
- {{jsxref("Array.prototype.push()")}} / {{jsxref("Array.prototype.pop()")}}
186+
- {{jsxref("Array.prototype.unshift()")}} / {{jsxref("Array.prototype.shift()")}}
187+
- {{jsxref("Array.prototype.concat()")}}
188+
- {{jsxref("Array.prototype.toSpliced()")}}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
title: Array.prototype.toReversed()
3+
slug: Web/JavaScript/Reference/Global_Objects/Array/toReversed
4+
page-type: javascript-instance-method
5+
browser-compat: javascript.builtins.Array.toReversed
6+
---
7+
8+
{{JSRef}}
9+
10+
The **`toReversed()`** method of an {{jsxref("Array")}} instance is the [copying](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#copying_methods_and_mutating_methods) counterpart of the {{jsxref("Array/reverse", "reverse()")}} method. It returns a new array with the elements in reversed order.
11+
12+
## Syntax
13+
14+
```js-nolint
15+
toReversed()
16+
```
17+
18+
### Return value
19+
20+
A new array containing the elements in reversed order.
21+
22+
## Description
23+
24+
The `toReversed()` method transposes the elements of the calling array object in reverse order and returns a new array.
25+
26+
When used on [sparse arrays](/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays), the `toReversed()` method iterates empty slots as if they have the value `undefined`.
27+
28+
The `toReversed()` method is [generic](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#generic_array_methods). It only expects the `this` value to have a `length` property and integer-keyed properties.
29+
30+
## Examples
31+
32+
### Reversing the elements in an array
33+
34+
The following example creates an array `items`, containing three elements, then creates a new array that's the reverse of `items`. The `items` array remains unchanged.
35+
36+
```js
37+
const items = [1, 2, 3];
38+
console.log(items); // [1, 2, 3]
39+
40+
const reversedItems = items.toReversed();
41+
console.log(reversedItems); // [3, 2, 1]
42+
console.log(items); // [1, 2, 3]
43+
```
44+
45+
### Using toReversed() on sparse arrays
46+
47+
The return value of `toReversed()` is never sparse. Empty slots become `undefined` in the returned array.
48+
49+
```js
50+
console.log([1, , 3].toReversed()); // [3, undefined, 1]
51+
console.log([1, , 3, 4].toReversed()); // [4, 3, undefined, 1]
52+
```
53+
54+
### Calling toReversed() on non-array objects
55+
56+
The `toReversed()` method reads the `length` property of `this`. It then visits each index between `length - 1` and `0` in descending order, and adds the value of that index in the original array to the corresponding index in the new array.
57+
58+
```js
59+
const arrayLike = {
60+
length: 3,
61+
unrelated: "foo",
62+
2: 4,
63+
};
64+
console.log(Array.prototype.toReversed.call(arrayLike));
65+
// [4, undefined, undefined]
66+
// The '0' and '1' indices are not present so they become undefined
67+
```
68+
69+
## Specifications
70+
71+
{{Specifications}}
72+
73+
## Browser compatibility
74+
75+
{{Compat}}
76+
77+
## See also
78+
79+
- [Polyfill of `Array.prototype.toReversed` in `core-js`](https://github.com/zloirock/core-js#change-array-by-copy)
80+
- {{jsxref("Array.prototype.reverse()")}}
81+
- {{jsxref("Array.prototype.toSorted()")}}
82+
- {{jsxref("Array.prototype.toSpliced()")}}
83+
- {{jsxref("Array.prototype.with()")}}
84+
- {{jsxref("TypedArray.prototype.toReversed()")}}

0 commit comments

Comments
 (0)