JS数据类型:数组方法splice、slice、concat
数组提供的方法有很多。为了方便起见,在本章中,我们将按组讲解。
添加/移除数组元素
我们已经学了从数组的首端或尾端添加和删除元素的方法:
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
元素被删除了,但数组仍然有 3 个元素,我们可以看到 arr.length == 3
。
这很正常,因为 delete obj.key
是通过 key
来移除对应的值。对于对象来说是可以的。但是对于数组来说,我们通常希望剩下的元素能够移动并占据被释放的位置。我们希望得到一个更短的数组。
所以应该使用特殊的方法。
arr.splice 方法可以说是处理数组的瑞士军刀。它可以做所有事情:添加,删除和插入元素。
语法是:
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"]
简单,对吧?从索引 1
开始删除 1
个元素。(译注:当只填写了 splice
的 start
参数时,将删除从索引 start
开始的所有数组项)
在下一个例子中,我们删除了 3 个元素,并用另外两个元素替换它们:
let arr = ["I", "study", "JavaScript", "right", "now"]; // 删除数组的前三项,并使用其他内容代替它们 arr.splice(0, 3, "Let's", "dance"); alert( arr ) // 现在 ["Let's", "dance", "right", "now"]
在这里我们可以看到 splice
返回了已删除元素的数组:
let arr = ["I", "study", "JavaScript", "right", "now"]; // 删除前两个元素 let removed = arr.splice(0, 2); alert( removed ); // "I", "study" <-- 被从数组中删除了的元素
我们可以将 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"
允许负向索引
在这里和其他数组方法中,负向索引都是被允许的。它们从数组末尾计算位置,如下所示:
let arr = [1, 2, 5]; // 从索引 -1(尾端前一位) // 删除 0 个元素, // 然后插入 3 和 4 arr.splice(-1, 0, 3, 4); alert( arr ); // 1,2,3,4,5
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 到尾端的元素)
我们也可以不带参数地调用它: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
通常,它只复制数组中的元素。其他对象,即使它们看起来像数组一样,但仍然会被作为一个整体添加:
let arr = [1, 2]; let arrayLike = { 0: "something", length: 1 }; alert( arr.concat(arrayLike) ); // 1,2,[object Object]
……但是,如果类似数组的对象具有 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