前情提要
在重学 Array 之一中,我们讲到了数组的基本概念,还有定义数组的两种方式。通过对一维数组的介绍,我们引出了对二维数组相关的知识的讲解,最后说到了数组中两个关键的属性 length 和下标,这两个属性在我们平时对数组的操作中起着关键的作用,当然他们的特性也是非常有意思的。关于具体的内容,大家可以回过头去看看重学 Array 之一的内容。
今天我们就来说说数组原型上对元素增删操作的相关方法吧!
元素增删
下面方法的介绍将按照字母顺序进行!
concat()
concat() 方法用于合并两个或多个数组。
⚠️注意:此方法不会更改现有数组,而是返回一个新数组
语法
const new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
concat() 方法会创建一个新的数组,它由被调用的对象中的元素组成,每个参数的顺序依次是该参数的元素(如果参数是数组)或参数本身(如果参数不是数组)。它不会递归到嵌套数组参数中。
concat() 方法不会改变 this 或任何作为参数提供的数组,而是返回一个浅拷贝,它包含与原始数组相结合的相同元素的副本。 原始数组的元素将复制到新数组中,如下所示:
对象引用(而不是实际对象):concat() 将对象引用复制到新数组中。 原始数组和新数组都引用相同的对象。 也就是说,如果引用的对象被修改,则更改对于新数组和原始数组都是可见的。 这包括也是数组的数组参数的元素。
数据类型如字符串,数字和布尔(不是String,Number 和 Boolean 对象):concat将字符串和数字的值复制到新数组中。
⚠️注意:数组/值在连接时保持不变。此外,对于新数组的任何操作(仅当元素不是对象引用时)都不会对原始数组产生影响,反之亦然。
示例
// 将两个数组合并成一个数组
[1, 2, 3].concat(['a', 'b']) // [1, 2, 3, "a", "b"]
// 将三个数组合并成一个数组
const arr1 = [1, 2, 3]
const arr2 = ['a', 'b', 'c']
const arr3 = ['!', '@']
arr1.concat(arr2, arr3)
// [1, 2, 3, "a", "b", "c", "!", "@"]
// 将三个值连接到数组
var alpha = ['a', 'b', 'c'];
var alphaNumeric = alpha.concat(1, [2, 3]);
console.log(alphaNumeric);
// results in ['a', 'b', 'c', 1, 2, 3]
// 合并数组并保留引用
var num1 = [[1]];
var num2 = [2, [3]];
var nums = num1.concat(num2);
console.log(nums);
// results in [[1], 2, [3]]
// 向 num1 数组的第一个元素 push 一个值
num1[0].push(4);
console.log(nums);
// [[1, 4], 2, [3]] 数组内引用的值改变了
pop()
pop() 方法从数组中删除最后一个元素,并返回该元素的值。
⚠️注意:此方法更改数组的长度
语法
arr.pop()
pop 方法有意具有通用性。该方法和 call() 或 apply() 一起使用时,可应用在类似数组的对象上。pop方法根据 length 属性来确定最后一个元素的位置。如果不包含 length 属性或 length 属性不能被转成一个数值,会将length 置为0,并返回 undefined。如果调用 pop() 方法的数组为空,它也返回 undefined。
示例
let myFish = ["angel", "clown", "mandarin", "surgeon"];
let popped = myFish.pop();
console.log(myFish);
// ["angel", "clown", "mandarin"]
console.log(popped);
// surgeon
push()
push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
语法
arr.push(element1, ..., elementN)
push() 方法有意具有通用性。该方法和 call() 或 apply() 一起使用时,可应用在类似数组的对象上。push() 方法根据 length 属性来决定从哪里开始插入给定的值。如果 length 不能被转成一个数值,则插入的元素索引为 0,包括 length 不存在时。当 length 不存在时,将会创建它。
⚠️注意:唯一的原生类数组(array-like)对象是 Strings,尽管如此,它们并不适用该方法,因为字符串是不可改变的。
示例
// 😁例子1:添加元素到数组
var sports = ["soccer", "baseball"];
var total = sports.push("football", "swimming");
console.log(sports);
// ["soccer", "baseball", "football", "swimming"]
console.log(total);
// 4
// 😁例子2:合并两个数组
var vegetables = ['parsnip', 'potato'];
var moreVegs = ['celery', 'beetroot'];
// 相当于 vegetables.push('celery', 'beetroot')
// 或者 vegetables.concat(moreVegs)
Array.prototype.push.apply(vegetables, moreVegs);
console.log(vegetables);
// ['parsnip', 'potato', 'celery', 'beetroot']
// 😁例子3:像数组一样操作对象
var obj = {
length: 0,
addElem: function addElem (elem) {
[].push.call(this, elem);
}
};
obj.addElem({});
obj.addElem({});
console.log(obj.length);
// 2
shift()
shift() 方法从数组中删除第一个元素,并返回该元素的值。
⚠️注意:此方法更改数组的长度
语法
arr.shift()
shift() 方法移除索引为 0 的元素(即第一个元素),并返回被移除的元素,其他元素的索引值随之减 1。如果 length 属性的值为 0 (长度为 0),则返回 undefined。
shift() 方法并不局限于数组,这个方法能够通过 call 或 apply 方法作用于类似数组的对象上。但是对于没有 length 属性(从0开始的一系列连续的数字属性的最后一个)的对象,调用该方法可能没有任何意义。
示例
let myFish = ['angel', 'clown', 'mandarin', 'surgeon'];
console.log('调用 shift 之前: ' + myFish);
// "调用 shift 之前: angel,clown,mandarin,surgeon"
var shifted = myFish.shift();
console.log('调用 shift 之后: ' + myFish);
// "调用 shift 之后: clown,mandarin,surgeon"
console.log('被删除的元素: ' + shifted);
// "被删除的元素: angel"
slice()
slice() 方法返回一个新的数组对象,这个对象是一个由 begin 和 end(不包括end)决定的原数组的浅拷贝。
⚠️注意:原始数组不会被改变
语法
arr.slice();
// [0, end]
arr.slice(begin);
// [begin, end]
arr.slice(begin, end);
// [begin, end)
begin:可选参数,从该索引处开始提取原数组中的元素(从0开始)。如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。如果省略 begin,则 slice 从索引 0 开始。
end:可选参数,在该索引处结束提取原数组元素(从0开始)。slice 会提取原数组中索引从 begin 到 end 的所有元素(包含begin,但不包含end)。slice(1, 4) 提取原数组中的第二个元素开始直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1) 表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。如果 end 被省略,则slice 会一直提取到原数组末尾。如果 end 大于数组长度,slice 也会一直提取到原数组末尾。
slice 不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。原数组的元素会按照下述规则拷贝:
如果该元素是个对象引用 (不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。
如果向两个数组任一中添加了新元素,则另一个不会受到影响。
示例
// 😁例子1:返回数组的一部分
var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(1, 3);
// fruits ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']
// citrus ['Orange','Lemon']
// 😁例子2:使用 slice 方法从 myCar 中创建一个 newCar.
var myHonda = { color: 'red', wheels: 4, engine: { cylinders: 4, size: 2.2 } };
var myCar = [myHonda, 2, "cherry condition", "purchased 1997"];
var newCar = myCar.slice(0, 2);
// 输出myCar, newCar,以及各自的myHonda对象引用的color属性.
console.log('myCar = ' + JSON.stringify(myCar));
console.log('newCar = ' + JSON.stringify(newCar));
console.log('myCar[0].color = ' + JSON.stringify(myCar[0].color));
console.log('newCar[0].color = ' + JSON.stringify(newCar[0].color));
// 改变myHonda对象的color属性.
myHonda.color = 'purple';
console.log('The new color of my Honda is ' + myHonda.color);
//输出myCar, newCar中各自的myHonda对象引用的color属性.
console.log('myCar[0].color = ' + myCar[0].color);
console.log('newCar[0].color = ' + newCar[0].color);
splice()
splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。
⚠️注意:此方法会改变原数组
语法
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
start:指定修改的开始位置(从 0 计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从 -1 计数,这意味着 -n 是倒数第 n 个元素并且等价于 array.length-n);如果负数的绝对值大于数组的长度,则表示开始位置为第 0 位。
deleteCount:可选参数,整数值,表示要移除的数组元素的个数。如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
item1, item2, …:可选要添加进数组的元素,从 start 位置开始。如果不指定,则 splice() 将只删除数组元素。
⚠️注意:如果添加进数组的元素个数不等于被删除的元素个数,数组的长度会发生相应的改变。
示例
// 😁例子1:从第 2 位开始删除 0 个元素,插入“drum”
var myFish = ["angel", "clown", "mandarin", "sturgeon"];
var removed = myFish.splice(2, 0, "drum");
// 运算后的 myFish: ["angel", "clown", "drum", "mandarin", "sturgeon"]
// 被删除的元素: [], 没有元素被删除
// 😁例子2:从第 2 位开始删除 0 个元素,插入“drum” 和 "guitar"
var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
var removed = myFish.splice(2, 0, 'drum', 'guitar');
// 运算后的 myFish: ["angel", "clown", "drum", "guitar", "mandarin", "sturgeon"]
// 被删除的元素: [], 没有元素被删除
// 😁例子3:从第 3 位开始删除 1 个元素
var myFish = ['angel', 'clown', 'drum', 'mandarin', 'sturgeon'];
var removed = myFish.splice(3, 1);
// 运算后的 myFish: ["angel", "clown", "drum", "sturgeon"]
// 被删除的元素: ["mandarin"]
// 😁例子4:从第 2 位开始删除 1 个元素,插入“trumpet”节
var myFish = ['angel', 'clown', 'drum', 'sturgeon'];
var removed = myFish.splice(2, 1, "trumpet");
// 运算后的 myFish: ["angel", "clown", "trumpet", "sturgeon"]
// 被删除的元素: ["drum"]
// 😁例子5:从第 0 位开始删除 2 个元素,插入"parrot"、"anemone"和"blue"节
var myFish = ['angel', 'clown', 'trumpet', 'sturgeon'];
var removed = myFish.splice(0, 2, 'parrot', 'anemone', 'blue');
// 运算后的 myFish: ["parrot", "anemone", "blue", "trumpet", "sturgeon"]
// 被删除的元素: ["angel", "clown"]
// 😁例子6:从第 2 位开始删除 2 个元素节
var myFish = ['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon'];
var removed = myFish.splice(myFish.length - 3, 2);
// 运算后的 myFish: ["parrot", "anemone", "sturgeon"]
// 被删除的元素: ["blue", "trumpet"]
// 😁例子7:从倒数第 2 位开始删除 1 个元素节
var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
var removed = myFish.splice(-2, 1);
// 运算后的 myFish: ["angel", "clown", "sturgeon"]
// 被删除的元素: ["mandarin"]
// 😁例子8:从第 2 位开始删除所有元素节
var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
var removed = myFish.splice(2);
// 运算后的 myFish: ["angel", "clown"]
// 被删除的元素: ["mandarin", "sturgeon"]
unshift()
unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度。
语法
arr.unshift(element1, ..., elementN)
unshift() 方法会在调用它的类数组对象的开始位置插入给定的参数。unshift() 特意被设计成具有通用性,这个方法能够通过 call 或 apply 方法作用于类数组对象上。不过对于没有 length 属性(代表从0开始的一系列连续的数字属性的最后一个)的对象,调用该方法可能没有任何意义。
⚠️注意:如果传入多个参数,它们会被以块的形式插入到对象的开始位置,它们的顺序和被作为参数传入时的顺序一致。 于是,传入多个参数调用一次 unshift ,和传入一个参数调用多次 unshift (例如,循环调用),它们将得到不同的结果。
示例
// 😁例子1:传入多个参数调用一次 unshift
let arr = [4,5,6];
arr.unshift(1,2,3); // 6
console.log(arr); // [1, 2, 3, 4, 5, 6]
// 传入一个参数调用多次 unshift
arr = [4,5,6]; // 重置数组
arr.unshift(1); // 4
arr.unshift(2); // 5
arr.unshift(3); // 6
console.log(arr); // [3, 2, 1, 4, 5, 6]
// 😁例子2:
let arr = [1, 2];
arr.unshift(0); // 3
// arr is [0, 1, 2]
arr.unshift(-2, -1); // 5
// arr is [-2, -1, 0, 1, 2]
arr.unshift([-4, -3]); // 6
// arr is [[-4, -3], -2, -1, 0, 1, 2]
arr.unshift([-7, -6], [-5]); // 8
// arr is [ [-7, -6], [-5], [-4, -3], -2, -1, 0, 1, 2 ]
总结
到这里,关于数组原型上七个关于元素增删操作的方法就说完了,都是一些比较简单的方法,其中 slice 和 splice 可能比较复杂一些,不错多跑点测试代码就好了。下一篇我们会说一些关于数组循环遍历的方法。