JS 数组的操作

184 阅读9分钟

在JavaScript中,数组支持在单个变量名下存储多个元素,是开发中常见的数据类型,这篇分享一些常用的操作数组的方法。

数组的创建

示例:

// 字面量方式:
var arr1 = [1, 2, 3]; // [1,2,3]

// 构造器:
var arr2 = new Array(); // []
var arr3 = new Array(3); // [,,]
var arr4 = new Array(1, 2, 3); // [1,2,3]

使用字面量和构造器创建的数组类似,都可以直接将值放进数组中;不同的是,当Array里只有一个值时,表示的是数组长度。

数组的操作

会改变原数组的操作

一、Array.push()

push()方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。

示例:

var arr = [1, 2, 3];

var arrLen = arr.push(4); // 追加单个元素
console.log(arr); // 1,2,3,4
console.log(arrLen); // 4

var arrLen = arr.push(5, 6); // 追加多个元素
console.log(arr); // 1,2,3,4,5,6

二、Array.pop()

pop()方法从数组中删除最后一个元素,并返回该元素的值,此方法会更改数组的长度。

示例:

var fruits = ['apple', 'banana', 'pear'];
console.log(fruits.pop()); // pear
console.log(fruits); // apple,banana

三、Array.shift()

shift()方法从数组中删除第一个元素,并返回该元素的值。此方法会更改数组的长度。

示例:

var fruits = ['apple', 'banana', 'pear'];
console.log(fruits.shift()); // apple
console.log(fruits); // banana,pear

四、Array.unshift()

unshift()方法将一个或多个元素添加到数组的开头,并返回该数组的新长度。

示例:

var fruits = ['apple', 'banana', 'pear'];
console.log(fruits.unshift('strawberry', 'pitaya')); // 5
console.log(fruits); // strawberry,pitaya,apple,banana,pear

五、Array.splice()

splice()方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

语法:

splice(start)
splice(start, deleteCount)
splice(start, deleteCount, item1)
splice(start, deleteCount, item1, item2, itemN)
  • start:指定修改的开始位置(下标)。如果超出数组长度,则从末尾开始添加内容;如果是负值,则表示从数组末尾开始第几位(从-1计数);如果复数的绝对值大于数组长度,则表示开始位置为第0位。
  • deleteCount:表示要移除的个数。如果大于数组长度,则start后面元素都被移除;如果是0或者负数,则不移除元素。
  • item1, item2,...:要添加进数组的元素,从start位置开始。如果不指定,则splice()将只删除数组元素。

示例:

var arr = [1, 7, 8, 4, 5, 6];
console.log(arr.splice(1, 2, 2, 3)); // 7,8
console.log(arr); // 1,2,3,4,5,6

六、Array.sort()

sort()方法用原地方法对数组的元素进行排序,并返回数组

注:若sort()方法没有传比较函数的话,默认按字母升序,如果元素不是字符串,会先转换为字符串后再比较

示例:

var arr1 = ['A', 'C', 'V', 'D', 'B'];
console.log(arr1.sort()); // A,B,C,D,V

var arr2 = [1, 10, 20, 100, 13, 2];
console.log(arr2.sort()); // 1,10,100,13,2,20

要让数字按照我们预想的方式排序,那就要用到比较函数

语法:

// 无函数
sort()

// 箭头函数
sort((a, b) => { /* 代码块 */ } )

// 比较函数
sort(compareFn)

// 内联比较函数
sort(function compareFn(a, b) { /* 代码块 */ })

比较函数的两个参数a和b,其中a表示第一个要比较的参数,b表示第二个要比较的参数。

  • 若比较函数返回值 < 0,那么a将排在b的前面;
  • 若比较函数返回值 = 0,那么a和b相对位置不变;
  • 若比较函数返回值 > 0,那么b将排在a的前面;

用法:

/* 对数组中的数字进行升序排序 */
var numbers = [1, 10, 20, 100, 13, 2];
numbers.sort(function (a, b) {
  return a - b;
});
console.log(numbers); // 1,2,10,13,20,100

/* 对数组中的数字进行降序排序 */
var numbers2 = [1, 10, 20, 100, 13, 2];
numbers2.sort(function (a, b) {
  return b - a;
});
console.log(numbers2); // 100,20,13,10,2,1

/* 对象可按照某个属性排序 */
var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];

// sort by value
items.sort((a, b) => a.value - b.value);

// sort by name
items.sort((a, b) => {
  var nameA = a.name.toUpperCase(); // 转大写
  var nameB = b.name.toUpperCase(); // 转大写
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }

  // names must be equal
  return 0;
});

七、Array.reverse()

reverse()方法将数组中元素的位置颠倒,并返回该数组。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组。

示例:

var arr = [1, 2, 3, 4, 5];
console.log(arr.reverse()); // 5,4,3,2,1
console.log(arr); // 5,4,3,2,1

八、Array.fill()

fill()方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素,但不包括终止索引。返回修改后的数组

语法:

fill(value)
fill(value, start)
fill(value, start, end)
  • value:用来填充数组元素的值。
  • start [可选]:起始索引,默认值为0。
  • end [可选]:终止索引,默认值为arr.length。

示例:

[1, 2, 3].fill(4);               // [4, 4, 4]
[1, 2, 3].fill(4, 1);            // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2);         // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1);         // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3);         // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2);       // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN);     // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5);         // [1, 2, 3]
Array(3).fill(4);                // [4, 4, 4]
[].fill.call({ length: 3 }, 4);  // {0: 4, 1: 4, 2: 4, length: 3}

// Objects by reference.
const arr = Array(3).fill({}) // [{}, {}, {}];
// 需要注意如果 fill 的参数为引用类型,会导致都执行同一个引用类型
// 如 arr[0] === arr[1] 为 true
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]

九、Array.copyWithin()

copyWithin()方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。

语法:

copyWithin(target)
copyWithin(target, start)
copyWithin(target, start, end)
  • target:0为基底的索引,复制序列到该位置。如果是负数,target将从末尾开始计算。如果target大于等于arr.length,将不会发生拷贝。如果target再start之后,复制的序列将被修改以符合arr.length.
  • start [可选]:0为基底的索引,开始复制元素的其实位置。如果是负数,start将从末尾开始计算。如果start被忽略,copyWithin将会从0开始复制。
  • end [可选]:0为基底的索引,开始复制元素的结束位置。copyWithin将会拷贝到该位置,但不包括end这个位置的元素。如果是负数,end将从末尾开始计算。如果end被忽略,copyWithin方法将会一直复制至数组结尾。

示例:

[1, 2, 3, 4, 5].copyWithin(-2); // [1, 2, 3, 1, 2]

[1, 2, 3, 4, 5].copyWithin(0, 3); // [4, 5, 3, 4, 5]

[1, 2, 3, 4, 5].copyWithin(0, 3, 4); // [4, 2, 3, 4, 5]

[1, 2, 3, 4, 5].copyWithin(-2, -3, -1); // [1, 2, 3, 3, 4]

[].copyWithin.call({length: 5, 3: 1}, 0, 3); // {0: 1, 3: 1, length: 5}

不会改变原数组的操作

一、Array.slice()

slice()方法返回一个新的数组对象,这一对象是一个由begin和end决定的原数组的浅拷贝(包括begin,不包括end)。原始数组不会被改变。

语法:

slice()
slice(start)
slice(start, end)
  • start [可选]:提取起始处的索引,从该索引开始提取原数组的元素。如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取。如果省略,则从索引0开始。如果超出原数组的索引范围,则会返回空数组。
  • end [可选]:提取终止处的索引,在该索引处结束提取原数组元素。如果该参数为负数,则它表示在原数组中的倒数第几个元素结束抽取。如果被省略或者于数组的长度,则一直提取到原数组末尾。

注:如果该元素是对象的引用,slice会拷贝这个对象的引用到新数组里。如果被引用的对象发生了改变,则新的数组和原数组中的这个元素也会发生改变。

示例:

var arr = ['hello', 'world'];

var newArr = arr.slice(0, 1);
console.log(arr); // hello,world
console.log(newArr); // hello

/* 如果是基本数据类型,改变新数组和原数组,两个数组互不干扰*/
arr[0] = 'hi';
newArr[0] = '你好';
console.log(arr); // hi,world
console.log(newArr); // 你好

/* 如果是复杂数据类型,其中一个改变,另一个也会改变 */
var objs = [{ name: 'Bob' }, { name: 'Alice' }];
var item = objs.slice(0);
console.log(item[0].name); // [{name: "Bob"}]

item[0].name = 'Steve';
console.log(objs[0].name); // [{name: "Steve"},{name: "Alice"}]

objs[0].name = 'David';
console.log(item[0].name); // [{name: "David"}]

二、Array.join()

join()方法将一个数组的所有元素连接成一个字符串并返回,用逗号或者指定的符号分割。如果数组只有一个元素,则不使用分隔符。

语法:

join()
join(separator)
  • separator [可选]:指定一个字符串来分割数组的每个元素。如果省略,则使用逗号分隔。如果使用(""),则元素间没有任何字符

示例:

var a = ['Wind', 'Water', 'Fire'];
a.join();      // 'Wind,Water,Fire'
a.join(', ');  // 'Wind, Water, Fire'
a.join(' + '); // 'Wind + Water + Fire'
a.join('');    // 'WindWaterFire'

二、Array.concat()

concat()方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

语法:

concat()
concat(value0)
concat(value0, value1)
concat(value0, value1, /* … ,*/ valueN)
  • valueN [可选]:数组或值,将被合并到新的数组中。如果省略参数,则会返回调用地方法的现存数组的一个浅拷贝。

注:concat将对象引用复制到新数组中。原始数组和新数组都引用相同的对象。也就是说,如果引用的对象被修改,则更改对于新数组和原始数组都是可见的。这包括也是数组的数组参数的元素。

示例:

/* 连接数组 */
var letters = ['a', 'b', 'c'];
var numbers = [1, 2, 3];

var alphaNumeric = letters.concat(numbers);
console.log(alphaNumeric); // results in ['a', 'b', 'c', 1, 2, 3]

/* 合并嵌套数组 */
var num1 = [[1]];
var num2 = [2, [3]];
var numbers = num1.concat(num2);
console.log(numbers); // results in [[1], 2, [3]]

// 修改 num1 的第一个元素
num1[0].push(4);
console.log(numbers); // results in [[1, 4], 2, [3]]

三、Array.indexOf()

indexOf()方法返回再数组中可以找到给定元素的第一个索引,如果不存在,则返回-1。

语法:

indexOf(searchElement)
indexOf(searchElement, fromIndex)
  • searchElement:要查找的元素。
  • fromIndex [可选]:开始查找的位置。如果 >= array.length,则不会在数组里查找,返回-1;如果是负值,从末尾开始往前跳fromIndex的绝对值个索引,然后向后搜索,即-1表示从最后一个元素开始。

示例:

var array = [2, 9, 9];
array.indexOf(2);     // 0
array.indexOf(7);     // -1
array.indexOf(9, 2);  // 2
array.indexOf(2, -1); // -1
array.indexOf(2, -3); // 0

四、Array.includes()

includes()方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回true,否则返回false。

语法:

includes(searchElement)
includes(searchElement, fromIndex)
  • searchElement:要查找的元素。
  • fromIndex [可选]:开始查找的位置。如果为负值,从末尾开始往前跳fromIndex的绝对值个索引,然后向后搜索。默认为0。

示例:

[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false
[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true