对JavaScript中数组的补完

50 阅读8分钟

数组

声明语法

let 数组名 = [数据1,数据2,...,数据n]

js的数组很像py的列表,但是更厉害之处是可以存不同数据类型,这也可能导致数据类型出错

可以使用下标索引 可以嵌套数组 可以自由拓展

关于数组的函数

以下是一些最常用的数组方法:

0. length返回长度
1. push() - 在数组末尾添加一个或多个元素,并返回新的长度
const fruits = ['apple', 'banana'];
let len = fruits.push('orange');
console.log(fruits);// 输出: ['apple', 'banana', 'orange']
console.log(len); //输出:3
2. pop() - 删除并返回数组的最后一个元素
const fruits = ['apple', 'banana', 'orange'];
const lastFruit = fruits.pop();
console.log(lastFruit); // 输出: 'orange'
console.log(fruits); // 输出: ['apple', 'banana']
3. unshift() - 在数组开头添加一个或多个元素,并返回新的长度
const numbers = [2, 3, 4];
numbers.unshift(1);
console.log(numbers); // 输出: [1, 2, 3, 4]
4. shift() - 删除并返回数组的第一个元素
const numbers = [1, 2, 3, 4];
const firstNumber = numbers.shift();
console.log(firstNumber); // 输出: 1
console.log(numbers); // 输出: [2, 3, 4]
5. indexOf() - 返回指定元素在数组中的第一个索引,如果不存在则返回 -1
const fruits = ['apple', 'banana', 'orange', 'apple'];
console.log(fruits.indexOf('banana')); // 输出: 1
console.log(fruits.indexOf('grape')); // 输出: -1
6. slice() - 返回数组的一个浅拷贝,包含从开始到结束(不包括结束)的元素
const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
console.log(animals.slice(2, 4)); // 输出: ['camel', 'duck']
7. splice() - 通过删除或替换现有元素和/或添加新元素来修改数组
const months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
console.log(months); // 输出: ['Jan', 'Feb', 'March', 'April', 'June']

对splice的拓展: 区别于delete操作符 因为delete会造成数组空洞,其他都是缩进 语法:

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

参数

  1. start: 指定修改的开始位置(从0计数)。
    1. 如果大于数组长度,则从数组末尾开始添加内容。
    2. 如果为负值,则表示从数组末位开始的第几位(从-1计数)。
  2. deleteCount (可选): 整数,表示要移除的元素个数。
    1. 如果省略,则默认从 start 到数组结尾的所有元素都将被删除。
  3. item1, item2, ... (可选): 要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。

返回值 splice() 方法返回一个由被删除的元素组成的数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

使用示例

  1. 删除元素
const fruits = ['apple', 'banana', 'orange', 'mango'];
const removed = fruits.splice(1, 2);

console.log(fruits);  // 输出: ['apple', 'mango']
console.log(removed); // 输出: ['banana', 'orange']
  1. 添加元素
const numbers = [1, 2, 5];
numbers.splice(2, 0, 3, 4);

console.log(numbers); // 输出: [1, 2, 3, 4, 5]

3. 替换元素

const colors = ['red', 'green', 'blue'];
colors.splice(1, 1, 'yellow', 'purple');

console.log(colors); // 输出: ['red', 'yellow', 'purple', 'blue']
  1. 使用负索引
const animals = ['lion', 'elephant', 'giraffe', 'zebra'];
animals.splice(-2, 1, 'hippo');

console.log(animals); // 输出: ['lion', 'elephant', 'hippo', 'zebra']
  1. 删除数组末尾的元素
const letters = ['a', 'b', 'c', 'd', 'e'];
letters.splice(3);

console.log(letters); // 输出: ['a', 'b', 'c']

注意事项

  1. splice() 方法会直接修改原数组。
  2. 如果你只想复制一个数组的一部分,而不修改原数组,可以使用 slice() 方法。
  3. 当用于大型数组时,splice() 可能会影响性能,因为它可能需要重新索引数组的大部分内容。

8. forEach() - 对数组的每个元素执行一次给定的函数
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => console.log(num * 2));
// 输出:
// 2
// 4
// 6
// 8
// 10

对于forEach()函数的进一步解释: 语法

array.forEach(callback(currentValue [, index [, array]])[, thisArg])

参数

  1. callback: 为数组中每个元素执行的函数,该函数接受一至三个参数:

    • currentValue: 数组中正在处理的当前元素。
    • index (可选): 数组中正在处理的当前元素的索引。
    • array (可选): forEach() 方法正在操作的数组。
  2. thisArg (可选): 执行 callback 函数时使用的 this 值。

返回值

forEach() 方法总是返回 undefined

使用示例

  1. 基本用法
const fruits = ['apple', 'banana', 'orange'];
fruits.forEach(function(fruit) {
    console.log(fruit);
});
// 输出:
// apple
// banana
// orange
  1. 使用箭头函数
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(number => console.log(number * 2));
// 输出:
// 2
// 4
// 6
// 8
// 10
  1. 使用索引参数
const colors = ['red', 'green', 'blue'];
colors.forEach((color, index) => {
    console.log(\`Color at index \${index} is \${color}\`);
});
// 输出:
// Color at index 0 is red
// Color at index 1 is green
// Color at index 2 is blue
  1. 修改原数组
const numbers = [1, 2, 3, 4, 5];
numbers.forEach((number, index, array) => {
    array[index] = number * 2;
});
console.log(numbers);
// 输出: [2, 4, 6, 8, 10]

5. 使用 thisArg

class Counter {
    constructor() {
        this.count = 0;
    }
    increment() {
        this.count++;
    }
}

const counter = new Counter();
const numbers = [1, 2, 3, 4, 5];

numbers.forEach(counter.increment, counter);

console.log(counter.count); // 输出: 5

注意事项

  1. forEach() 不会修改原数组(除非在回调函数中执行修改操作)。
  2. forEach() 总是会遍历整个数组,无法中途停止(除非抛出异常)。如果需要中途停止遍历,可以考虑使用 for 循环或 some()every() 等其他数组方法。
  3. forEach() 不会对未初始化的值进行操作。
  4. forEach() 是同步方法,不适合处理异步操作。对于异步操作,可以考虑使用 for...of 循环或 Promise.all()
  5. map() 不同,forEach() 没有返回值。如果需要根据原数组创建新数组,应该使用 map()

9. map() - 创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后的返回值
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // 输出: [2, 4, 6, 8, 10]

对map()函数的进一步解释: 语法:

let newArray = arr.map(callback(currentValue[, index[, array]]) {
  // return element for newArray
}[, thisArg])

参数

  1. callback: 生成新数组元素的函数,使用三个参数:
    • currentValue: 数组中正在处理的当前元素。
    • index (可选): 数组中正在处理的当前元素的索引。
    • array (可选): map 方法被调用的数组。
  2. thisArg (可选): 执行 callback 函数时使用的 this 值。

返回值

一个新数组,每个元素都是回调函数的结果。

使用示例

  1. 基本用法:将数字数组中的每个元素翻倍
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(num => num * 2);

console.log(doubledNumbers); // 输出: [2, 4, 6, 8, 10]
  1. 处理对象数组:提取特定属性
const users = [
  { name: 'John', age: 30 },
  { name: 'Jane', age: 28 },
  { name: 'Bob', age: 35 }
];

const names = users.map(user => user.name);

console.log(names); // 输出: ['John', 'Jane', 'Bob']

3. 使用索引参数

const letters = ['a', 'b', 'c'];
const indexedLetters = letters.map((letter, index) => \`\${letter.toUpperCase()}\${index}\`);

console.log(indexedLetters); // 输出: ['A0', 'B1', 'C2']
  1. 在 React 中渲染列表
function App() {
  const items = ['Apple', 'Banana', 'Orange'];
  
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
}

5. 链式调用

const numbers = [1, 2, 3, 4, 5];
const result = numbers
  .map(num => num * 2)
  .filter(num => num > 5)
  .reduce((acc, num) => acc + num, 0);

console.log(result); // 输出: 21

注意事项

  1. map() 不会修改原数组。它创建一个新数组,不会对原数组产生副作用。
  2. map() 对数组中的每个元素都会调用一次提供的函数。
  3. 如果原数组中包含未定义的元素,map() 在迭代时会跳过它们,但新数组中仍会保留这些位置,值为 undefined
  4. 当你不需要返回值,只想遍历数组执行某些操作时,应该使用 forEach() 而不是 map()
  5. map() 常常与其他数组方法(如 filter()reduce())一起使用,形成强大的数据处理管道。
  6. 在处理大型数组时,考虑使用 for 循环来优化性能,因为 map() 会创建一个新数组。

下面是高级用法:

  1. reduce() - 对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // 输出: 15
  1. some() - 测试数组中是不是至少有1个元素通过了被提供的函数测试
const numbers = [1, 2, 3, 4, 5];
const hasEvenNumber = numbers.some(num => num % 2 === 0);
console.log(hasEvenNumber); // 输出: true
  1. every() - 测试一个数组内的所有元素是否都能通过某个指定函数的测试
const numbers = [1, 2, 3, 4, 5];
const allPositive = numbers.every(num => num > 0);
console.log(allPositive); // 输出: true
  1. find() - 返回数组中满足提供的测试函数的第一个元素的值
const numbers = [1, 2, 3, 4, 5];
const firstEven = numbers.find(num => num % 2 === 0);
console.log(firstEven); // 输出: 2
  1. findIndex() - 返回数组中满足提供的测试函数的第一个元素的索引
const fruits = ['apple', 'banana', 'orange', 'grape'];
const index = fruits.findIndex(fruit => fruit === 'orange');
console.log(index); // 输出: 2
  1. includes() - 判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false
const fruits = ['apple', 'banana', 'orange'];
console.log(fruits.includes('banana')); // 输出: true
console.log(fruits.includes('grape')); // 输出: false
  1. flat() - 按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回
const arr = [1, 2, [3, 4, [5, 6]]];
console.log(arr.flat(2)); // 输出: [1, 2, 3, 4, 5, 6]
  1. flatMap() - 首先使用映射函数映射每个元素,然后将结果压缩成一个新数组
const arr = [1, 2, 3, 4];
const result = arr.flatMap(x => [x, x * 2]);
console.log(result); // 输出: [1, 2, 2, 4, 3, 6, 4, 8]
  1. from() - 从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
const set = new Set(['foo', 'bar', 'baz', 'foo']);
const arr = Array.from(set);
console.log(arr); // 输出: ["foo", "bar", "baz"]