跳至主要內容

数组

wzCoding大约 14 分钟JavaScript数组

数组

数组 也是我们在开发中使用到的最多的数据结构之一,它本质上也是一个对象,但与对象不同的是,数组是一个有序的集合

创建数组

创建数组有两种方式:

  • 直接创建(字面量)
    let arr = [1, 2, 3];
    console.log(arr); // [1, 2, 3]
    
  • 使用构造函数创建
    let arr = new Array(1, 2, 3);
    console.log(arr); // [1, 2, 3]
    

数组是有顺序的,它的索引从0开始(索引也被称为下标),一直到数组的最后一个元素结束(arr.length - 1

访问数组

访问或修改数组中的元素,可以通过数组的下标来操作,下标就是数组的索引

let arr = [1, 2, 3];
console.log(arr[0]); // 1
console.log(arr[1]); // 2
arr[2] = 4;
console.log(arr); // [1, 2, 4]

通过索引来访问数组元素的方式与访问对象属性的方式十分类似,数组的索引就相当于对象的 key,而数组中的元素就相当于对象的 value

length 属性

length 属性表示数组的长度,即数组中元素的个数

let arr = [1, 2, 3];
console.log(arr.length); // 3

当我们修改数组的时候,数组的 length 属性会自动更新,数组的 length 属性是可写的,我们可以通过修改 length 属性的值来修改数组的长度

let arr = [1, 2, 3];
arr[5] = 6;
console.log(arr.length); // 6
console.log(arr); // [1, 2, 3, empty × 2, 6]

当数组的 length 属性被修改的时候,数组的长度会自动更新,如果修改后的 length 属性值小于原数组的长度,那么数组中多出的元素会被删除,所以清空一个数组最简单的方法就是将 length 属性的值设置为 0

let arr = [1, 2, 3];
arr.length = 2;
console.log(arr.length); // 2
console.log(arr); // [1, 2]
arr.length = 0;
console.log(arr.length); // 0
console.log(arr); // []

遍历数组

我们可以使用 for 循环遍历数组

  • for 循环遍历:使用 for 循环遍历数组时需要设置合适的循环条件
    let arr = [1, 2, 3];
    for (let i = 0; i < arr.length; i++) {
      console.log(arr[i]);
    }
    // 1
    // 2
    // 3
    
  • for...of 循环遍历:使用 for...of 循环遍历数组时获取的是数组元素,无法获取数组元素的索引
    let arr = [1, 2, 3];
    for (let item of arr) {
      console.log(item);
    }
    // 1
    // 2
    // 3
    
  • for...in 循环遍历:for...in 循环主要是用来遍历对象,但数组本质上也是对象,所以也可以使用 for...in 循环,但是一般不建议这样使用,因为 for...in 循环会遍历数组中的所有属性,包括数组的 length 属性
    let arr = [1, 2, 3];
    for (let key in arr) {
      console.log(arr[key]);
    }
    // 1
    // 2
    // 3
    

数组方法

数组 Array 为我们提供了许多内置的方法,这些方法都在 Array 的原型对象上,我们可以直接通过数组调用这些方法

push()

push() 方法用于向数组的末尾添加一个或多个元素,并返回修改后数组的长度

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

pop()

pop() 方法用于删除数组的最后一个元素,并返回删除的元素

let arr = [1, 2, 3];
arr.pop();
console.log(arr); // [1, 2]
console.log(arr.pop()); // 2
console.log(arr); // [1]

shift()

shift() 方法用于删除数组的第一个元素,并返回删除的元素

let arr = [1, 2, 3];
arr.shift();
console.log(arr); // [2, 3]
console.log(arr.shift()); // 1
console.log(arr); // [3]

unshift()

unshift() 方法用于向数组的头部添加一个或多个元素,并返回修改后数组的长度

let arr = [1, 2, 3];
arr.unshift(0);
console.log(arr); // [0, 1, 2, 3]
console.log(arr.unshift(-1)); // 5
console.log(arr); // [-1, 0, 1, 2, 3]

splice()

splice() 方法用于删除、插入、替换数组的元素,并返回被删除、插入、替换的元素,他会改变原有数组。它接收3个参数,具体用法如下:

  • splice(start):删除从 start 索引开始的元素
  • splice(start, deleteCount):删除从 start 索引开始的 deleteCount 个元素
  • splice(start, deleteCount, item1, item2, ...):删除从 start 索引开始的 deleteCount 个元素,并插入 item1, item2, ... 元素
let arr = [1, 2, 3, 4, 5];
arr.splice(2); // 从索引为2开始删除所有元素
console.log(arr); // [1, 2]
arr.splice(2, 2, 6, 7); // 从索引为2开始删除2个元素,并插入6和7
console.log(arr); // [1, 2, 6, 7]
arr.splice(3,1); // 从索引为3的元素开始删除一个元素
console.log(arr); // [1, 2, 6, 7]

slice()

slice() 方法用于从数组中截取指定索引范围内的元素,并返回一个新的数组,slice 方法接收2个参数,具体用法如下:

  • slice(start):从 start 索引开始截取到数组的末尾
  • slice(start, end):从 start 索引开始截取到 end 索引结束

start 参数可以取负值,表示从数组的末尾开始计算索引,当 start 小于 0 时,start 参数的计算方式是 start + arr.lengthend 参数可以省略,当省略 end 参数时,end 参数的计算方式是 arr.length

let arr = [1, 2, 3, 4, 5];
let newArr = arr.slice(1, 3);
console.log(newArr); // [2, 3]
console.log(arr.slice(2)) // ==> slice(2, 5) [3, 4, 5]
console.log(arr.slice(2, 1)) // []
console.log(arr.slice(-1)) // ==> slice((-1 + 5), 5) [5]

concat()

concat() 方法用于将多个数组拼接成一个新数组,并返回拼接后的数组

let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let newArr = arr1.concat(arr2);
console.log(newArr); // [1, 2, 3, 4, 5, 6]

join()

join() 方法用于将数组中的元素拼接成一个字符串,并返回拼接后的字符串,它接收一个指定的分隔符作为参数,会使用传入的分隔符对数组元素进行分隔, 默认使用 , 作为分隔符

let arr = [1, 2, 3];
let str = arr.join();
console.log(str); // "1,2,3"
let str2 = arr.join('-');
console.log(str2); // "1-2-3"

reverse()

reverse() 方法用于将数组中的元素反转,并返回反转后的数组,此操作会改变原数组

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

sort()

sort() 方法用于对数组中的元素进行排序,并返回排序后的数组,它接收一个排序函数作为参数,根据排序函数的返回值对数组元素进行排序(默认排序是将元素转换为字符串,然后按照它们的 UTF-16 码元值升序排序),此操作会改变原数组

排序函数的返回值可以是以下几种情况:

  • 如果返回值大于 0,则表示第一个元素应该排在第二个元素之后
  • 如果返回值小于 0,则表示第一个元素应该排在第二个元素之前
  • 如果返回值等于 0,则表示两个元素的位置不变
let arr = [3, 1, 2];
arr.sort();
console.log(arr); // [1, 2, 3]
arr.sort(function(a, b) {
  return a - b;
});
console.log(arr); // [1, 2, 3]
arr.sort(function(a, b) {
  return b - a;
});
console.log(arr); // [3, 2, 1]

map()

map() 方法用于对数组中的每个元素进行操作,并返回一个新的数组,它接收一个处理函数作为参数,处理函数的参数包括 currentValue(当前元素)、index(当前元素的索引)、array(原数组),处理函数的返回值会作为新数组中的每个元素

let arr = [1, 2, 3];
let newArr = arr.map(function(item, index, array) {
  return item * 2;
});
console.log(newArr); // [2, 4, 6]

filter()

filter() 方法用于对数组中的每个元素进行条件判断,并返回一个新的数组,它接收一个处理函数作为参数,处理函数的参数包括 currentValue(当前元素)、index(当前元素的索引)、array(原数组),新数组中的元素都是满足处理函数条件的元素

let arr = [1, 2, 3, 4, 5];
let newArr = arr.filter(function(item) {
  return item > 3;
});
console.log(newArr); // [4, 5]

every()

every() 方法用于对数组中的每个元素进行条件判断,并返回一个布尔值,它接收一个处理函数作为参数,处理函数的参数包括 currentValue(当前元素)、index(当前元素的索引)、array(原数组),如果数组中的所有元素都满足处理函数的条件,则返回 true,否则返回 false

let arr = [1, 2, 3, 4, 5];
let result = arr.every(function(item) {
  return item > 0;
});
console.log(result); // true

some()

some() 方法用于对数组中的每个元素进行条件判断,并返回一个布尔值,它接收一个处理函数作为参数,处理函数的参数包括 currentValue(当前元素)、index(当前元素的索引)、array(原数组),如果数组的所有元素中至少有一个元素满足处理函数的条件,则返回 true,否则返回 false

let arr = [1, 2, 3, 4, 5];
let result = arr.some(function(item) {
  return item > 3;
});
console.log(result); // true

reduce()

reduce() 方法用于对数组中的每个元素进行累加操作,并返回累加后的结果,它接收一个处理函数和一个初始值作为参数,它不会改变原数组,处理函数的参数包括:

  • accumulator:上次累加的结果(在第一次调用时如果指定了初始值,则为初始值,否则为数组中第一个元素的)
  • currentValue:当前元素(在第一次调用时如果指定了初始值,则为数组中第一个元素,否则为数组中第二个元素)
  • currentIndex:currentValue 在数组中的索引(在第一次调用时如果指定了初始值,则为0,否则为1)
  • array:原数组
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce(function(accu, curr) {
  return accu + curr;
});
console.log(result); // 15

forEach()

forEach() 方法用于对数组中的每个元素进行操作,但不返回任何结果,它接收一个处理函数作为参数,处理函数的参数包括 currentValue(当前元素)、index(当前元素的索引)、array(原数组)

let arr = [1, 2, 3, 4, 5];
arr.forEach(function(item) {
  console.log(item);
});
// 1
// 2
// 3
// 4
// 5

indexOf()

indexOf() 方法用于查找给定元素第一次出现在数组中的索引,如果查找到该元素,返回该元素的索引,否则返回 -1,它接收2个参数,具体用法如下:

  • indexOf(searchElement):查找给定元素第一次出现在数组中的索引
  • indexOf(searchElement, fromIndex):查找给定元素第一次出现在数组中的索引,从 fromIndex 索引开始查找
let arr = [1, 2, 3, 4, 5];
console.log(arr.indexOf(3)); // 2
console.log(arr.indexOf(4,3)) // 3
console.log(arr.indexOf(6)); // -1

lastIndexOf()

lastIndexOf() 方法与 indexOf() 方法类似,不同的是 lastIndexOf() 方法是从数组的最后一个元素开始查找指定元素的索引,并返回该元素的索引,如果数组中不存在该元素,则返回 -1,它的参数与 indexOf() 方法相同

let arr = [1, 2, 3, 4, 5];
console.log(arr.lastIndexOf(3)); // 2
console.log(arr.indexOf(4,3)) // 3
console.log(arr.lastIndexOf(6)); // -1

find()

find() 方法用于查找数组中满足指定条件的第一个元素,并返回该元素的值,如果数组中不存在满足条件的元素,则返回 undefined,它接收一个处理函数作为参数,处理函数的参数包括 currentValue(当前元素)、index(当前元素的索引)、array(原数组)

let arr = [1, 2, 3, 4, 5];
console.log(arr.find(function(item) {
  return item > 3;
})); // 4

findIndex()

findIndex() 方法与 find() 方法类似,不同的是 findIndex() 方法返回满足指定条件的第一个元素的索引,如果数组中不存在满足条件的元素,则返回 -1

let arr = [1, 2, 3, 4, 5];
console.log(arr.findIndex(function(item) {
  return item > 3;
})); // 3

fill()

fill() 方法用于将数组中的所有元素填充为指定的值,并返回填充后的数组,他会改变原数组,它接收3个参数,具体用法如下:

  • fill(value):将数组中的所有元素填充为指定的值
  • fill(value, start):从 start 索引开始填充数组,如果 start 小于 0,则 start 参数的计算方式是 start + arr.length
  • fill(value, start, end):从 start 索引开始填充数组,到 end 索引结束,如果 start 小于 0,则 start 参数的计算方式是 start + arr.length,如果 end 小于 0,则 end 参数的计算方式是 end + arr.length
let arr = [1, 2, 3, 4, 5];
arr.fill(0);
console.log(arr); // [0, 0, 0, 0, 0]
arr.fill(1, 2);
console.log(arr); // [1, 1, 0, 0, 0]
arr.fill(2, 1, 3);
console.log(arr); // [1, 2, 2, 0, 0]

flat()

flat() 方法用于将嵌套的数组扁平化,即按照给定的展开层数将子数组中的元素添加到新数组中,它接收一个指定的展开层数作为参数,如果展开层数为 Infinity,则表示将所有子数组中的元素添加到新数组中,并返回扁平化后的数组,它不会改变原数组

  let arr = [1, 2, [3, 4], [5, [6, 7]]];
  let newArr = arr.flat();
  console.log(newArr); // [1, 2, 3, 4, 5, [6, 7]]

entries()

entries() 方法用于返回数组中每个元素的键值对,并返回一个迭代器对象,可以使用 for...of 循环遍历迭代器对象获取每个元素的键值对

let arr = ['a', 'b', 'c'];
let iterator = arr.entries();
for (let item of iterator) {
  console.log(item); // ['0', 'a'] ['1', 'b'] ['2', 'c']
}

类数组

在 JavaScript 中,类数组(Array-like Object)是一种类似数组的对象,它具有一个 length 属性,并且可以通过索引访问元素,但是它没有数组的一些方法,例如 push()pop() 等,它通常是通过其他对象(例如 DOM 元素)的属性或方法来实现的。

常见的类数组对象有:

  • arguments 对象
  • NodeList 对象
  • HTMLCollection 对象
  • 字符串
  • Set 对象
  • Map 对象

可以使用 Array.from() 方法将类数组对象转换为数组,或者使用 Array.prototype.slice.call() 方法将类数组对象转换为数组

let arrayLike = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};
let arr = Array.from(arrayLike);
console.log(arr); // ['a', 'b', 'c']
let arr2 = Array.prototype.slice.call(arrayLike);
console.log(arr2); // ['a', 'b', 'c']

数组去重

数组去重是前端开发中常见的需求,可以使用多种方法对数组进行去重操作。

  • Set 方法
  • filter 方法
  • map 方法
  • reduce 方法
  • indexOf 方法
  • includes 方法
  • Object 方法
  • 双重循环 方法

Set 方法

Set 方法是一种数据结构,它类似于数组,但是其中的元素都是唯一的,它可以用于对数组进行去重操作。

let arr = [1, 2, 3, 4, 5, 1, 2, 3];
let uniqueArr = [...new Set(arr)];
console.log(uniqueArr); // [1, 2, 3, 4, 5]

filter 方法

filter 方法用于过滤数组中的元素,并返回一个新的数组,新数组中的元素都是满足指定条件的元素。

  let arr = [1, 2, 3, 4, 5, 1, 2, 3];
  let uniqueArr = arr.filter((item, index) => {
    return arr.indexOf(item) === index;
  });
  console.log(uniqueArr); // [1, 2, 3, 4, 5]

map 方法

map 方法用于对数组中的每个元素进行操作,并返回一个新的数组,新数组中的元素都是处理函数的返回值。

let arr = [0, 1, 2, 3, 4, 5, 1, 2, 3, 6, 7];
let uniqueArr = arr.map((item, index,array) => {
  return array.indexOf(item) === index ? item : undefined;
}).filter(item => item !== undefined) 
console.log(uniqueArr); // [0, 1, 2, 3, 4, 5, 6, 7]

reduce 方法

reduce 方法用于对数组中的每个元素进行累加操作,并返回累加后的结果。

let arr = [1, 2, 3, 4, 5, 1, 2, 3];
let uniqueArr = arr.reduce((accu, item) => {
  if (!accu.includes(item)) {
    accu.push(item);
  }
  return accu;
}, []);
console.log(uniqueArr); // [1, 2, 3, 4, 5]

indexOf 方法

indexOf 方法用于查找给定元素第一次出现在数组中的索引,如果查找到该元素,返回该元素的索引,否则返回 -1。

let arr = [1, 2, 3, 4, 5, 1, 2, 3];
let uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
  if (uniqueArr.indexOf(arr[i]) === -1) {
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // [1, 2, 3, 4, 5]

includes 方法

includes 方法用于判断数组中是否包含给定的元素,如果包含该元素,则返回 true,否则返回 false

let arr = [1, 2, 3, 4, 5, 1, 2, 3];
let uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
  if (!uniqueArr.includes(arr[i])) {
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // [1, 2, 3, 4, 5]

Object 方法

可以将不重复的数组元素保存在对象中,使用 Object.keys() 或者 Object.values() 方法来获取不重复的元素

let arr = [1, 2, 3, 4, 5, 1, 2, 3];
let obj = {};
for (let i = 0; i < arr.length; i++) {
  if (!obj.hasOwnProperty(arr[i])) {
    obj[arr[i]] = arr[i];
  }
}
let uniqueArr = Object.values(obj)
console.log(uniqueArr); // [1, 2, 3, 4, 5]

双重循环

双重循环是一种比较低效的方法,它需要遍历数组中的每个元素,并判断该元素是否已经存在于新数组中。

let arr = [1, 2, 3, 4, 5, 1, 2, 3];
let uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
  let isUnique = true;
  for (let j = 0; j < uniqueArr.length; j++) {
    if (arr[i] === uniqueArr[j]) {
      isUnique = false;
      break;
    }
  }
  if (isUnique) {
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // [1, 2, 3, 4, 5]