数组方法
# 移除 / 添加数组元素
除了:
arr.push(...items)—— 从尾端添加元素,arr.pop()—— 从尾端提取元素,arr.shift()—— 从首端提取元素,arr.unshift(...items)—— 从首端添加元素。
还会见到其他方法。
# splice
如何从数组当中删除元素?
数组是对象,所以可尝试delete:
let arr = ["I", "go", "home"];
delete arr[1]; // remove "go"
alert( arr[1] ); // undefined
// now arr = ["I", , "home"];
alert( arr.length ); // 3
2
3
4
5
6
7
8
元素被删除了,但数组仍然有 3个元素,我们可以看到 arr.length == 3。
这很正常,因为 delete obj.key 是通过 key 来移除对应的值。对于对象来说是可以的。但是对于数组来说,我们通常希望剩下的元素能够移动并占据被释放的位置。我们希望得到一个更短的数组。
所以应该使用特殊的方法。
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 个元素
alert( arr ); // ["I", "JavaScript"]
2
3
4
5
简单,对吧?从索引 1 开始删除 1 个元素。
在下一个例子中,我们删除了 3 个元素,并用另外两个元素替换它们:
let arr = ["I", "study", "JavaScript", "right", "now"];
// 删除索引为3的前面加所有元素,并替换为传入的相应参数
arr.splice(0, 3, "Let's", "dance");
alert( arr ) // now ["Let's", "dance", "right", "now"]
2
3
4
5
6
在这里我们可以看到 splice 返回了已删除元素的数组:
let arr = ["I", "study", "JavaScript", "right", "now"];
// 删除前两个元素
let removed = arr.splice(0, 2);
alert( removed ); // "I", "study" <-- 被从数组中删除了的元素
2
3
4
5
6
我们可以将 deleteCount 设置为 0,splice 方法就能够插入元素而不用删除任何元素:
let arr = ["I", "study", "JavaScript"];
// 从索引 2 开始
// 删除 0 个元素
// 然后插入 "complex" 和 "language"
arr.splice(2, 0, "complex", "language");
alert( arr ); // "I", "study", "complex", "language", "JavaScript"
2
3
4
5
6
7
8
允许负向索引
在这里和其他数组方法中,负向索引都是被允许的。它们从数组末尾计算位置,如下所示:
let arr = [1, 2, 5]; // 从索引 -1(尾端前一位) // 删除 0 个元素, // 然后插入 3 和 4 arr.splice(-1, 0, 3, 4); alert( arr ); // 1,2,3,4,51
2
3
4
5
6
7
8
# slice
arr.slice比arr.splice简单的多。
语法是:
arr.slice([start], [end]);
它会返回一个新数组,将所有从索引 start 到 end(不包括 end)的数组项复制到一个新的数组。start 和 end 都可以是负数,在这种情况下,从末尾计算索引。
它和字符串的 str.slice 方法有点像,就是把子字符串替换成子数组。
例如:
let arr = ["t", "e", "s", "t"];
alert(arr.slice(1, 3)); // e,s(复制从位置 1 到位置 3 的元素)
alert(arr.slice(-2)); // s,t(复制从位置 -2 到尾端的元素)
2
3
4
5
我们也可以不带参数地调用它:arr.slice() 会创建一个 arr 的副本。其通常用于获取副本,以进行不影响原始数组的进一步转换。
# concat
arr.concat创建一个新数组,其中包含来自于其他数组和其他项的值。
语法:
arr.concat(arg1, arg2...)
它接受任意数量的参数 —— 数组或值都可以。
结果是一个包含来自于 arr,然后是 arg1,arg2 的元素的新数组。
如果参数 argN 是一个数组,那么其中的所有元素都会被复制。否则,将复制参数本身。
例如:
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
};
alert( 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
};
alert( 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)) {
// 在这里可以做某件事情,比如对某个或每个元素进行一些操作
}
2
3
# 在数组中搜索
搜索或者过滤
indexOf/lastIndexOf/Includes
arr.indexOf(item, from)从索引from开始搜索item,如果找到则返回索引,否则返回-1。arr.lastIndexOf(item, from)—— 和上面相同,只是从右向左搜索。arr.includes(item, from)—— 从索引from开始搜索item,如果找到则返回true(译注:如果没找到,则返回false)。
let arr = [1, 0, false];
alert( arr.indexOf(0) ); // 1
alert( arr.indexOf(false) ); // 2
alert( arr.indexOf(null) ); // -1
alert( arr.includes(1) ); // true
2
3
4
5
6
7
请注意,这些方法使用的是严格相等 === 比较。所以如果我们搜索 false,会精确到的确是 false 而不是数字 0。
如果我们想检查是否包含某个元素,并且不想知道确切的索引,那么 arr.includes 是首选。
此外,includes 的一个非常小的差别是它能正确处理NaN,而不像 indexOf/lastIndexOf:
const arr = [NaN];
alert( arr.indexOf(NaN) ); // -1(应该为 0,但是严格相等 === equality 对 NaN 无效)
alert( arr.includes(NaN) );// true(这个结果是对的)
2
3