本文翻译自:JavaScript Array Methods: Mutating vs. Non-Mutating
JavaScript 提供了许多方式去增加、删除和替换数组中的元素,有些会作用到原数组本身,有些则不是——它们会返回一个新数组。
接下来,我会分别列举如何使用变异或非变异方法来实现这三个操作。文章末尾还会展示如何通过非变异方法 array.map()
来遍历数组并转化其中的元素。
虽然在这我没有列举一个详尽的列表,但是下面基本包含了数组所有的基础操作方式。
注意:接下来的内容中,当需要使用非变异方法时,我会使用 const
来声明数组,否则会用 let
。尽管你可以改变一个用 const
声明的数组而且也不会抛错,但我还是喜欢用 const
显式地告诉大家这个值不会改变。
警告:看这篇文章的时候,要特别留意它们的区别:
array.splice()
会改变原始数组,而array.slice()
则不会改变原始数组。
增加元素:变异方法
为数组增加元素的变异方法是 array.push()
和 array.unshift()
。
// since the array will be mutated,
// use 'let' rather than 'const'
let mutatingAdd = ['a', 'b', 'c', 'd', 'e'];
mutatingAdd.push('f'); // ['a', 'b', 'c', 'd', 'e', 'f']
mutatingAdd.unshift('z'); // ['z', 'a', 'b', 'c', 'd', 'e']
上面的代码:
array.push()
增加一个元素到数组末尾array.unshift()
增加一个元素到数组开头
增加元素:非变异方法
有两个办法可以在不改变原始数组的情况下增加元素。
第一个是 array.concat()
。
// since we will not be mutating,
// use const
const arr1 = ['a', 'b', 'c', 'd', 'e'];
const arr2 = arr1.concat('f'); // ['a', 'b', 'c', 'd', 'e'. 'f']
console.log(arr1); // ['a', 'b', 'c', 'd', 'e']
第二个方法需要借助 JavaScript 的展开运算符。展开运算符是数组前的三个点(...
)。
// since we will not be mutating,
// use const
const arr1 = ['a', 'b', 'c', 'd', 'e'];
const arr2 = [...arr1, 'f']; // ['a', 'b', 'c', 'd', 'e', 'f']
const arr3 = ['z', ...arr1]; // ['z', 'a', 'b', 'c', 'd', 'e']
向上面这样使用展开运算符时,将会从原数组中拷贝所有元素放到新的数组中。
在第 5 行,我们从 arr1
取得了所有元素的拷贝,然后放到了新数组中,最后把 'f'
放在末尾。
在第 6 行,过程与上面一样,只不过新元素 'z'
放在了数组中其它元素的前面。
删除元素:变异方法
为数组删除元素的变异方法是 array.pop()
和 array.shift()
。
// since the array will be mutated,
// use 'let' rather than 'const'
let mutatingRemove = ['a', 'b', 'c', 'd', 'e'];
mutatingRemove.pop(); // ['a', 'b', 'c', 'd']
mutatingRemove.shift(); // ['b', 'c', 'd']
上面的代码:
array.pop()
删除数组中的最末的元素array.shift()
删除数组中开头的元素
array.pop()
和 array.shift()
方法都返回被删除的元素。所以你可以抓取删除的元素并存到一个变量上。
let mutatingRemove = ['a', 'b', 'c', 'd', 'e'];
const returnedValue1 = mutatingRemove.pop();
console.log(mutatingRemove); // ['a', 'b', 'c', 'd']
console.log(returnedValue1); // 'e'
const returnedValue2 = mutatingRemove.shift();
console.log(mutatingRemove); // ['b', 'c', 'd']
console.log(returnedValue2); // 'a'
还可以用 array.splice()
来删除数组中的多个元素。
let mutatingRemove = ['a', 'b', 'c', 'd', 'e'];
mutatingRemove.splice(0, 2); // ['c', 'd', 'e']
这里的 mutatingRemove.splice(0, 2)
使用了两个参数(也可以是多个参数,下面还会再提到它)。
- 第一个参数是
splice
的起始索引位置。 - 第二个参数是想要删除的数量。
在上面的例子里,从 mutatingRemove
数组中删除了两个(第二个参数)元素,删除的元素起始于索引 0
(第一个参数)。
就像 array.pop()
和 array.shift()
一样,array.splice()
方法同样返回被删除的元素。
let mutatingRemove = ['a', 'b', 'c', 'd', 'e'];
let returnedItems = mutatingRemove.splice(0, 2);
console.log(mutatingRemove); // ['c', 'd', 'e']
console.log(returnedItems) // ['a', 'b']
删除元素:非变异方法
JavaScript 中的 array.filter()
方法会从原数组中创建一个新数组,但是这个新数组只包含符合特定要求的元素。
// since we will not be mutating,
// use const
const arr1 = ['a', 'b', 'c', 'd', 'e'];
const arr2 = arr1.filter(a => a !== 'e'); // ['a', 'b', 'd', 'f']
// OR
const arr2 = arr1.filter(a => {
return a !== 'e';
}); // ['a', 'b', 'd', 'f']
上面的代码中,条件是「!== 'e'
」,所以新数组(arr2
)跟原始数组类似,只是仅包含符合「 !== 'e'
」条件的元素。
*一些箭头函数的特性:
在单行箭头函数(第 5 行)中,「return」关键字是隐式存在的,所以不需要显式写出来。
但是,在多行箭头函数(第 7~9 行)中,你需要显式的返回一个值。
另一种删除数组元素的非变异方法是使用 array.slice()
(不要跟 array.splice()
搞混了)。
array.slice()
接受两个参数。
- 第一个参数是开始拷贝的起始索引位置。
- 第二个参数是拷贝结束的索引位置。结束位置的元素并不会包含进去(前开后闭)。
// since we will not be mutating,
// use const
const arr1 = ['a', 'b', 'c', 'd', 'e'];
const arr2 = arr1.slice(1, 5) // ['b', 'c', 'd', 'e']
const arr3 = arr1.slice(2) // ['c', 'd', 'e']
上面的第 4 行(const arr2 = arr1.slice(1, 5)
),arr2
是由自 arr1
的索引 1
起,到 5
之前(例如索引 4
)的元素拷贝而来。
第 5 行(const arr3 = arr1.slice(2)
)是一种常见的方式。如果使用 array.slice()
没有传入第二个参数,那么该方法会从传入的索引起一直拷贝到数组结束。
替换元素:变异方法
如果你知道要替换的元素索引,那么可以直接用 array.splice()
去替换。
所以,我们需要至少三个参数来完成它。
- 第一个参数是开始替换的索引位置。
- 第二个参数是想要删除的元素个数。
- 第三个之后的参数是想要插入到数组中的元素。
// since the array will be mutated,
// use 'let' rather than 'const'
let mutatingReplace = ['a', 'b', 'c', 'd', 'e'];
mutatingReplace.splice(2, 1, 30); // ['a', 'b', 30, 'd', 'e']
// OR
mutatingReplace.splice(2, 1, 30, 31); // ['a', 'b', 30, 31, 'd', 'e']
第 4 行(mutatingReplace.splice(2, 1, 30)
)将 'c'
替换为 30
。
第 6 行(mutatingReplace.splice(2, 1, 30, 31)
)删除了 'c'
,然后又插入了 30
和 31
两个元素。
替换元素:非变异方法
我们可以使用 array.map()
来创建一个新数组,同时我们还能检查每一个元素或者按照特定要求来替换元素。
// since we will not be mutating,
// use const
const arr1 = ['a', 'b', 'c', 'd', 'e']
const arr2 = arr1.map(item => {
if(item === 'c') {
item = 'CAT';
}
return item;
}); // ['a', 'b', 'CAT', 'd', 'e']
上面的代码基于 arr1
创建了一个新数组,并把所有的 'c'
都替换成了 'CAT'
。
通过 array.map()
转换数据
array.map()
是一个强大的方法,可以在不影响原始数据的前提下做数据转换。
// since we will not be mutating,
// use const
const origArr = ['a', 'b', 'c', 'd', 'e'];
const transformedArr = origArr.map(n => n + 'Hi!'); // ['aHi!', 'bHi!', 'cHi!', 'dHi!', 'eHi!']
// OR
const transformedArr = origArr.map(n => {
return n * 2;
})// ['aHi!', 'bHi!', 'cHi!', 'dHi!', 'eHi!']
console.log(origArr); // ['a', 'b', 'c', 'd', 'e']; // orignal array is intact
-- EOF --
好