数组方法
# 移除 / 添加数组元素
除了:
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,5
1
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