本文翻译自: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 --
好