🔃 JavaScript 数组
JavaScript 的数组元素都是按顺序排列,对比 对象 ,数组是 有序集合 。
# 数组的声明 / 访问
创建空数组的两种方法:
let arr = new Array(); let arr = [];
1
2
🌰 例子 / 一般常用第二种语法声明数组:
let fruits = ["Apple", "Orange", "Plum"];
🌰 例子 / 使用 new
方法创建数组可能存在问题:
点击查看
对于普通的字符串创建数组,可以直接作为 new Array()
的参数:
let arr = new Array("Apple", "Pear", "etc");
但是当参数为数字时,此时数字意味着指定数组的长度,创建空数组,而不是创建带有该参数的数组。注意区分!
let arr = new Array(2);
console.log(arr.length) // 2
2
获取数组中的元素:使用方括号加索引值
[]
(数组元素从 0 索引)console.log(fruits[0]) // 'Apple'
1替换数组中的元素:直接访问数组元素,赋上新的值(区别于字符串,字符串不能这样操作)
fruits[2] = 'Pear'; // after: fruits = ["Apple", "Pear", "Plum"];
1获取数组的长度:(与字符串相同,自带属性
length
):console.log(fruits.length) // 3
1直接打印数组的内容:(与对象区分,对象需要重写
toString
方法才能打印内容,下文有关于数组的toString
方法详细介绍)console.log(fruits) // Apple,Orange,Plum
1数组可以存储任何类型的元素:(单一类型或者混合类型都可以,甚至是对象、函数类型)
let arr = [ 'Apple', { name: 'John' }, true, function() { alert('hello'); } ]; console.log((arr[1].name)) // 获取数组中对象的属性的值 arr[3](); // 执行数组中元素的函数
1
2
3
4
# 数组的基本操作
如果想要获取数组的 最后一个元素 。不可以
fruits[-1]
,因为在 JavaScript 中方括号的索引是按照其字面意思处理的,结果为undefined
,只可以fruits[fruits.length - 1]
通过获取数组长度显示计算索引。
⭐️ 使用
at()
获取数组元素(最近版本更新) 可以直接使用-1
:console.log(fruits.at(-1)) // 'Plum'
1对于
at()
:i >= 0
,则与arr[i]
完全相同。i
为负数的情况,它则从数组的尾部向前数。
JavaScript 中的数组既可以用作队列,也可以用作栈。它们允许你从首端 / 末端来添加 / 删除元素。(可以看作数组为双向队列)
队列使用数组的两个方法:
shift()
在数组首端取出一个元素(出队)。push()
在数组首端添加一个元素(入队)。
栈使用数组的两个方法:
push()
在数组末端添加一个元素(进栈)。pop()
在数组末端移除一个元素(推栈)。
进一步深入了解数组的方法:
# 作用于 数组末端 的方法
pop()
:取出并返回数组的最后一个元素。(影响原数组)push(...)
:在数组末端添加元素。(无返回值,参数为要添加的元素)(相当于arr[arr.length + 1 ] = ...
)
# 作用于 数组首端 的方法
shift()
:取出并返回数组的第一个元素。unshift()
:在数组首端添加元素。
🌰 例子 / 使用 push()
/ unshift()
一次添加多个元素:
let fruits = ["Apple"];
fruits.push("Orange", "Peach");
fruits.unshift("Pineapple", "Lemon");
console.log(fruits) // ["Pineapple", "Lemon", "Apple", "Orange", "Peach"]
2
3
4
5
6
🌰 例子 / 接收用户输入的数(判断)求和:
点击查看
function sum() {
let sum = 0;
let arr = [];
while(true) {
let value = prompt('input number', 0)
if(value === '' || value === null || isFinite(value)) break;
value = +value // 处理为数字类型
arr.push(value)
}
for(value of arr) {
sum += value
}
return sum;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 理解数组的内部
数组是一种特殊的对象。使用方括号来访问属性 arr[0]
实际上是来自于对象的语法。它其实与 obj[key]
相同,其中 arr
是对象,而数字用作键(key)。
数组扩展了对象,提供了特殊的方法来处理有序的数据集合以及 length
属性。但从本质上讲,它仍然是一个对象。
JavaScript 只有 8 种基本的数据类型。其中数组仍属于对象类型。行为也与对象相似。
# 数组的复制
与对象的引用复制相同原理。
🌰 例子:
let fruits = ["Banana"]
let arr = fruits; // 实际上,两个数组引用同一个数组
console.log(arr === fruits) // true
arr.push("Pear");
console.log(fruits) // Banana, Pear
2
3
4
5
6
数组真正特殊的是它们的内部实现。JavaScript 引擎尝试把这些元素一个接一个地存储在 连续的内存区域,还有一些其它的优化,以使数组运行得非常快。
但如果破坏数组的连续性去使用数组,例如直接访问远超出初始索引的值,或者给数组对象添加属性,针对数组的优化就不再适用了,然后对应的优化就会被关闭,数组不将存在优势。
- 添加一个非数字的属性,比如
arr.test = 5
。- 制造空洞,比如:添加
arr[0]
,然后添加arr[1000]
(它们中间什么都没有)。- 以倒序填充数组,比如
arr[1000]
,arr[999]
等等。
注意
所以数组最好作用于 有序数据 的特殊结构,以正确的方式使用数组,才能发挥数组最大的优势。如果需要任意键值,那使用常规的对象。
# 数组的性能
可以从数据结构的「时间复杂度」思考:( push/pop
方法运行的比较快,而 shift/unshift
比较慢)
- 从首端操作,要从首端开始向后(或从后端向前端)推移元素, 数组里的元素越多,移动它们就要花越多的时间,也就意味着越多的内存操作 。
- 而从数组的末端操作,意味着 不需要移动任何元素 。 因为其它元素都保留了各自的索引。这就是为什么
pop
/push
的操作会特别快。
# 数组的循环
经典方式 / 使用
for
的 完整形式 循环:let arr = ["Apple", "Orange", "Pear"]; for (let i = 0; i < arr.length; i++) { console.log(arr[i]); }
1
2
3
4
5使用
for…of
循环:for (let fruit of fruits) { console.log( fruit ); }
1
2
3注意:
for..of
不能获取当前元素的索引,只是获取元素值。根据对象特性使用
for…in
:for (let key in arr) { alert( arr[key] ); // Apple, Orange, Pear }
1
2
3使用
for…in
会带来潜在的问题:for..in
循环会遍历 所有属性,不仅仅是这些数字属性。对于浏览器和其它环境中的「类数组」对象,会有其它的非数字的属性和方法。这些额外的循环是不必要的。for..in
循环适用于普通对象,并且做了对应的优化,但是不适用于数组。
所以不应该使用
for…in
处理数组。
# 数组的长度 length
当修改数组的时候, length
属性会自动更新。实际上 length
不是数组里元素的个数,而是最大的数字索引值加一。
🌰 例子 / 一个数组只有一个元素,但是这个元素的索引值很大,那么这个数组的 length
也会很大:
let fruits = [];
fruits[123] = "Apple";
console.log( fruits.length );
2
3
4
但是通常都不会这样使用数组。
🌰 例子 / 手动修改 length
:
let arr = [1, 2, 3, 4, 5];
arr.length = 2; // 截断到只剩 2 个元素
alert( arr ); // [1, 2]
arr.length = 5; // 又把 length 加回来
alert( arr[3] ); // undefined
2
3
4
5
6
7
可以看到,这个修改的过程是不可逆的。
利用 length
,清空数组的最简单的方法是 arr.length = 0
。
# 多维数组
数组里的项也可以是数组。可以用来创建 矩阵:
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
console.log( matrix[1][1] ); // 5
2
3
4
5
6
7
# 数组的 toString()
数组自己的 toString
方法的实现,会返回 以逗号隔开的元素列表字符串。
🌰 例子 / 打印数组:
let arr = [1, 2, 3];
console.log( arr ); // 1,2,3
console.log( String(arr) === '1,2,3' );
2
3
4
🌰 例子 / 数组的打印结果拼接字符串:
console.log( [] + 1 ); // "1"
console.log( [1] + 1 ); // "11"
console.log( [1,2] + 1 ); // "1,21"
2
3
对于数组,没有
Symbol.toPrimitive
,也没有valueOf
,它们只能执行toString
进行转换,所以这里[]
就变成了一个空字符串,[1]
变成了"1"
,[1,2]
变成了"1,2"
。
# 数组的比较
JavaScript 中的数组 不能使用 ==
运算符比较,该运算符不会对数组进行特殊处理,它会像 处理任意对象 那样处理数组。
在对象中:
- 仅当两个对象引用的是同一个对象时,它们才相等
==
。- 如果
==
左右两个参数之中有一个参数是对象,另一个参数是原始类型,那么该对象将会被转换为原始类型。- 严格比较
===
更简单,不会进行类型转换。
使用 ==
比较数组,除非引用的是同一个数组对象,否则尽管数组的内容相同(实质上仍然不是同一个对象),比较结果永远都不会相等。
console.log([] == []) // 与原始对象比较 alert( 0 == [] ); // true []被转换为空字符串'' alert('0' == [] ); // false
1
2
3
4
5
# 数组的更多方法
# 添加 / 移除数组元素
# 🍎 splice
arr.splice (opens new window) 方法可以说是处理数组的瑞士军刀,它可以做所有事情:添加,删除和插入元素。语法如下:
arr.splice(start[, deleteCount, elem1, ..., elemN])
它从索引 start
开始修改 arr
:删除 deleteCount
个元素并在当前位置插入 elem1, ..., elemN
。最后 返回已被删除元素的数组。
🌰 例子 / 删除数组元素:
let arr = ["I", "study", "JavaScript"];
arr.splice(1, 1); // 从索引 1 开始删除 1 个元素
console.log(arr) // ["I", "JavaScript"]
2
3
当参数只有
start
,从start
索引开始删除所有的数组元素。
🌰 例子 / 删除数组元素并替换:
let arr = ["I", "study", "JavaScript", "right", "now"];
// 删除数组的前三项,并使用其他内容代替它们
let removed = arr.splice(0, 3, "Let's", "dance");
console.log(arr) // ["Let's", "dance", "right", "now"]
console.log(removed) // ["I", "study"]
2
3
4
5
🌰 例子 / 在指定位置新增元素:
let arr = ["I", "study", "JavaScript"];
// 从索引 2 开始
// 删除 0 个元素
// 然后插入 "complex" 和 "language"
arr.splice(2, 0, "complex", "language");
console.log(arr) // ["I", "study", "complex", "language", "JavaScript"]
2
3
4
5
6
7
提示
区别于方括号访问,数组的方法中可以使用「负向索引」,即索引值可以为负数,从数组末尾计算位置。
let arr = [1, 2, 5];
// 从索引 -1(尾端前一位)
// 删除 0 个元素,
// 然后插入 3 和 4
arr.splice(-1, 0, 3, 4);
console.log(arr); // 1,2,3,4,5
2
3
4
5
6
7
# slice
用于切割数组,将所有从索引 start
到 end
( ⚠️ 不包括 end
)的数组项复制到一个新的数组,返回这个新的数组。
arr.slice([start], [end])
与字符串的
str.slice
相似。
🌰 例子:
let arr = ["t", "e", "s", "t"];
console.log(arr.slice(1, 3)) // 'e' 's'
2
🌰 例子 / 不含参数的 slice()
获取原数组的副本,在此副本进行的操作不会影响原来的数组:
console.log(arr.slice) // ['t', 'e', 's', 't']
🌰 例子 / 从末尾开始索引(即使是末尾索引但不代表反过来切割):
console.log(arr.slice(-2)) s,t
# concat
拼接数组,用于创建一个新的数组,包含来自其他数组和其他项的值。可以接受 任意参数 (数组或者值)。结果是包含来自于 arr
、 arg1
、 arg2
等元素的新数组。如果参数 argN
是一个数组,那么其中的 所有元素 都会被复制。如果不是数组,将复制 参数本身(例如对象,即便其中有类似数组的结构,仍然会作为一个整体添加)。
arr.concat(arg1, arg2...)
🌰 例子 :
let arr = [1, 2];
// create an array from: arr and [3,4]
alert( arr.concat([3, 4]) ); // 1,2,3,4
// create an array from: arr and [3,4] and [5,6]
alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6
// create an array from: arr and [3,4], then add values 5 and 6
alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6
2
3
4
5
6
7
8
9
10
🌰 例子:复制其他对象:
let arr = [1, 2];
let arrayLike = {
0: "something",
length: 1
};
console.log(arr.concat(arrayLike)) // 1,2,[object Object]
2
3
4
5
6
7
8
🌰 例子:如果类似数组的对象具有 Symbol.isConcatSpreadable
的属性,则可以被 concat
当作一个数组处理:
let arr = [1, 2];
let arrayLike = {
0: "something",
1: "else",
[Symbol.isConcatSpreadable]: true,
length: 2
};
console.log(arr.concat(arrayLike)); // 1,2,something,else
2
3
4
5
6
7
8
9
10
# forEach
遍历
使用 arr.forEach()
允许为数组的 每一个元素 都运行一个函数:
arr.forEach(function(item, index, array) {
// ... do something with item
});
2
3
🌰 例子 / 对每一个元素都运行 alert()
:
["Bilbo", "Gandalf", "Nazgul"].forEach(alert);
🌰 例子 / 打印详细信息:
["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => {
console.log(`${item} is at index ${index} in ${array}`);
});
2
3
# 搜索数组
# indexOf
/ lastIndexOf
和 includes
与字符串的用法基本相同:
arr.indexOf(item, from)
: 从索引from
开始搜索item
,如果找到则 返回索引 ,否则返回-1
。arr.lastIndexOf(item, from)
:逆序搜索。找到 返回索引,否则返回-1
。arr.includes(item, from)
:从索引from
开始搜索item
,如果找到则返回true
,否则返回false
。
🌰 例子 :
let arr = [1, 0, false];
console.log(arr.indexOf(0)) // 1
console.log(arr.lsatIndexOf(false)) // 0
console.log(arr.includes(0)) // true
2
3
4
⚠️ 注意:这些方法使用的是 严格相等 ===
比较。所以如果搜索 false
,会精确到的确是 false
而不是数字 0
。
🌰 例子: includes
它能正确处理 NaN
,不像 indexOf/lastIndexOf
:
const arr = [NaN];
alert( arr.indexOf(NaN) ); // -1(应该为 0,但是严格相等对 NaN 无效)
alert( arr.includes(NaN) );// true
2
3
# find
/ findIndex
在对象数组中要找到特定的对象使用 find
,依次对数组中的 每个元素 调用该函数:
let result = arr.find(function(item, index, array) {
// item 元素,index 索引, array 数组本身
// 如果返回 true,则返回 item 并停止迭代
// 没有搜索到,则返回 undefined
});
2
3
4
5
🌰 例子 :
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
let result = users.find(item => item.id == 1)
2
3
4
5
6
7
最常用的用法就是使用
item
去筛选条件,返回筛选后的结果(index
和array
不常用)。
findIndex
与 find
方法基本上是一样的,但它返回找到元素的索引,而不是元素本身。并且在未找到任何内容时返回 -1
。
# 🍎 filter
find
方法只会找到使函数返回 true
的 第一个(单个)元素。如果需要匹配的元素有很多,可以使用 filter
方法,语法与 find
方法大致相同, filter
返回的是 所有匹配元素组成的数组 。
let results = arr.filter(function(item, index, array) {
// 如果为 true , item 被 push 到 results,迭代继续
// 如果什么都没找到,则返回空数组
});
2
3
4
🌰 例子 :
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
let res = users.filter((item) => item.id < 2)
console.log(res) // [{id: 1, name: "John"}, {id: 2, name: "Pete"},]
2
3
4
5
6
7
8
# 转换数组
# 🍎 map
是最常使用、最有用的数组方法。对数组的每个元素都调用函数,并返回结果数组。
let result = arr.map(function(item, index, array) {
// 返回新值而不是当前元素
})
2
3
🌰 例子 / 将每个元素转换为它的字符串长度:
let lengths = ["Bilbo", "Gandalf", "Nazgul"].map((item)=> item.length)
console.log(lengths) // 5,7,6
2
# 数组排序
# 🍎 sort(fn)
该方法对数组进行 原位(in-place) 排序,更改元素的顺序。
原位:在此数组排序,并非生成新的数组。
🌰 例子:
let arr = [15, 1, 2]
arr.sort()
console.log(arr) // 1, 15, 2
2
3
注意:以上排序结果并非按照数字大小顺序排序,这些元素默认情况下被按字符串进行排序。 所有元素都被转换为字符串,然后进行比较。
如果要想要按照定义的排序顺序,需要提供一个函数作为 arr.sort()
的参数。该函数应该比较两个任意值并返回:
function compare(a, b){
if(a > b) return 1;
if(a == b) return 0;
if(a < b) return -1;
}
let arr = [1, 2, 15]
arr.sort(compare)
console.log(arr) // 1, 2, 15
2
3
4
5
6
7
8
9
由于数组可以由任何内容组成的数组,可能包含数字、字符串、对象或其他任何内容。要对这些不同类型的元素排序,需要一个 排序函数 来确认如何比较这些元素。数组默认是按字符串进行排序的。
arr.sort(fn)
遍历数组,使用提供的函数比较其元素并对其重新排序。比较函数只需要返回一个正数表示「大于」,一个负数表示「小于」。
🌰 例子 / 常用比较大小函数(从小到大)(简化为 箭头函数 版本):
[5,4,3,2,1].sort((a, b) => a - b)
# reverse()
用于 颠倒 数组中的顺序(原位修改)。
🌰 例子 :
let arr = [1, 2, 3, 4, 5]
arr.reverse();
console.log(arr) // 5,4,3,2,1
// let res = arr.reverse()
// console.log(res) // 返回值也可以接收结果
2
3
4
5
6
# 🍎 数组拆分 / 组合 split
/ join
str.split(delim)
方法用于 字符串 上,通过给定的分隔符 delim
将字符串分割成一个数组。(字符串分割为数组)
🌰 例子 :
let names = 'Bilbo, Gandalf, Nazgul';
let arr = names.split(', ');
for (let name of arr) {
console.log(name)
}
2
3
4
5
split()
的第二个可以选择的参数,是对数组长度的限制。如果提供了,那么额外的元素会被忽略。但实际上它很少使用。
🌰 例子:
let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2);
console.log(arr); // Bilbo, Gandalf
2
🌰 例子 / 第一个参数为空字符串,将字符串拆分为字母数组:
let str = "test";
console.log(str.split('')); // t,e,s,t
2
arr.join(glue)
与 split
相反,它会在它们之间创建一串由 glue
粘合的 arr
项。(数组粘合为字符串)
🌰 例子:
let arr = ['Bilbo', 'Gandalf', 'Nazgul'];
let str = arr.join(';'); // 使用分号 ; 将数组粘合成字符串
console.log(str); // Bilbo;Gandalf;Nazgul
2
3
# 🍎 reduce
/ reduceRight
这个函数一个接一个地应用于所有数组元素,并将其结果「搬运」到下一个调用。语法如下:
let value = arr.reduce(function(accumulator, item, index, array) {
// ...
}, [initial]);
2
3
参数:
accumulator
:(累加器)是上一个函数调用的结果,第一次等于initial
(如果提供了initial
的话)。item
:当前的数组元素。index
:当前索引。arr
:数组本身。
🌰 例子 / 通过 reduce
计算数组元素总和:
let arr = [1, 2, 3, 4, 5]
let res = arr.reduce((sum, cur) => sum + cur, 0)
console.log(res) // 15
2
3
sum
是累加器,cur
是当前的元素,0
是累加器的初始值。通常只需要这两个参数即可。
也可以省略初始值,数组的第一个元素作为初始值,第二个元素开始迭代,得出的结果相同:
let res = arr.reduce((sum, cur) => sum + cur)
注意省略初始值使用的情况不能为数组为空时,当数组为空时,第一个累加器返回的就是空值导致出错。所以始终建议指定初始值。
arr.reduceRight (opens new window) 和 arr.reduce (opens new window) 方法的功能一样,只是遍历为 从右到左。
# Array.isArray()
由于数组是基于对象的,不构成单独的语言类型,所以 typeof
不能帮助 从数组中区分出普通对象。Array.isArray(value) (opens new window) 用于检验一个对象是否为数组,如果 value
是一个数组,则返回 true
;否则返回 false
。
🌰 例子:
console.log(Array.isArray({})) // false
console.log(Array.isArray([])) // true
2
# thisArg
参数
几乎所有 调用函数的数组方法 , 比如 find
, filter
, map
,除了 sort
是一个 特例,都接受一个 可选的附加参数 thisArg
。由于较少使用所以涉及以上数组方法并没有介绍。
完整的用法:
arr.find(func, thisArg);
arr.filter(func, thisArg);
arr.map(func, thisArg);
// ...
2
3
4
thisArg
最后可选参数的值在 func
中变为 this
。
🌰 例子 / 使用 army
对象方法作为 过滤器, thisArg
用于传递上下文:
let army = {
minAge: 18,
maxAge: 27,
canJoin(user) {
return user.age >= this.minAge && user.age < this.maxAge;
}
};
let users = [
{age: 16},
{age: 20},
{age: 23},
{age: 30}
];
// *找到 army.canJoin 返回 true 的 user
let soldiers = users.filter(army.canJoin, army)
alert(soldiers.length); // 2
alert(soldiers[0].age); // 20
alert(soldiers[1].age); // 23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
实际中,为了可读性,可以写成:
users.filter(user => army.canJoin(user))
1
# 数组总结
关于数组的方法备忘录:
添加 / 移除元素相关:
🍎
push(...items)
:向 尾端 添加元素。🍎
pop()
:从 尾端 提取一个元素。🍎
shift()
:从 首端 提取一个元素。🍎
unshift(...items)
:向 首端 添加元素。🍎
splice(pos, deleteCount, ...items)
: 从pos
开始删除deleteCount
个元素,并插入items
。🍎
slice(start, end)
:创建一个新数组,将从索引start
到索引end
(但不包括end
)的元素 复制 进去。concat(...items)
:返回一个新数组:复制 当前数组的所有元素,并向其中添加items
。如果items
中的任意一项是一个数组,那么就取其元素。(其他对象则为对象本身)
查找元素相关:
indexOf
/lastIndexOf(item, pos)
:从索引pos
开始搜索item
,搜索到则返回该项的 索引值,否则返回-1
。includes(value)
:如果数组有value
,则返回true
,否则返回false
。- 🍎
find(func)
: 通过func
过滤元素,返回使func
返回true
的 第一个值。 - 🍎
filter(func)
: 通过func
过滤元素,返回使func
返回true
的 所有值。 findIndex
和find
类似,但返回 索引 而不是值。
遍历元素相关:
- 🍎
forEach(func)
—— 对每个元素都调用func
,不返回任何内容
- 🍎
转换数组相关:
- 🍎
map(func)
: 根据对每个元素调用func
的结果创建一个新数组。 - 🍎
sort(func)
: 对数组进行 原位排序,然后返回排序后的数组。 reverse()
: 原位反转 数组,然后返回反转后的数组。- 🍎
split/join
:将字符串 转换为数组 并返回。 - 🍎
reduce
/reduceRight(func, initial)
:通过对每个元素调用func
计算数组上的单个值,并在调用之间传递中间结果。(常见用法累加)
- 🍎
其他:
Array.isArray(arr)
:检查arr
是否是一个数组。
补充数组方法:
- 🍎
arr.some(fn)
/arr.every(fn)
检查数组。对数组的每个元素调用函数fn
:- 有一
true
所有就返回true
:如果fn
返回一个真值,arr.some()
立即返回true
并停止迭代其余数组项; - 所有
true
才返回true
:如果fn
返回一个假值,arr.every()
立即返回false
并停止对其余数组项的迭代。
- 有一
🌰 例子 / 使用 every()
检验数组是否全等:
function compareArray(arr1, arr2){
return arr1.length && arr2.length && arr1.every((value, index) => value === arr2[index])
}
compareArray([1,2], [1,2]) // true
2
3
4
5
arr.fill(value, start, end)
:从索引start
到end
,用重复的value
填充数组。arr.copyWithin(target, start, end)
:将从位置start
到end
的所有元素复制到 自身 的target
位置(覆盖现有元素)。arr.flat(depth)
/arr.flatMap(fn)
: 从多维数组创建一个新的扁平数组。Array.of(element0[, element1[, …[, elementN]]])
: 基于 可变数量的参数 创建一个新的Array
实例,而不需要考虑参数的数量或类型。