無.Flac's Blog

無.Flac

JavaScript - 数组

2024-12-26

⭐️ 有关JavaScript的学习总结



数组(Array)

>简介

数组也是一种复合数据类型,在数组可以存储多个不同类型的数据。

数组中存储的是有序的数据,数组中的每个数据都有一个唯一的索引,可以通过索引来操作获取数据。

数组中存储的数据叫做元素,索引(index)是一组大于 0 的数。

length是用来获取数组的长度。

- 创建数组
    通过Array()来创建数组,也可以通过[]来创建数组

    const arr = new Array()
  
- 向数组中添加元素
    语法:
        数组[索引] = 元素

    arr[0] = 10
    arr[1] = 22
    arr[2] = 44
    arr[3] = 88
    arr[4] = 99
 // arr[100] = 99  // 使用数组时,应该避免非连续数组,因为它性能不好
    const arr2 = [1, 2, 3, 4, 5] // 数组字面量

- 读取数组中的元素
    语法:
        数组[索引]
        - 如果读取了一个不存在的元素,不好报错而是返回undefined

    console.log(typeof arr) // object

- length
    - 获取数组的长度,实际值就是数组的最大索引 + 1
      console.log(arr)

    - 向数组最后添加元素:==> 数组[数组.length] = 元素
      arr[arr.length] = 55
      arr[arr.length] = 99

    - length是可以修改的
      arr.length = 5 //改大会让数组变大多出很多空元素,改小则会减少多出的元素

>遍历数组

遍历数组简单理解,就是获取到数组中的每一个元素

// 任何类型的值都可以成为数组中的元素
let arr = [1, "hello", true, null, { name: "孙悟空" }, () => {}]

// 创建数组时尽量要确保数组中存储的数据的类型是相同
arr = ["孙悟空", "猪八戒", "沙和尚"]

// console.log(arr[0])
// console.log(arr[1])
// console.log(arr[2])

arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]

for(let i=0; i<arr.length; i++){
    console.log(arr[i])
}

 for (let i = arr.length - 1; i >= 0; i--) {
     console.log(arr[i])
}
/* 
    定义一个Person类,类中有两个属性name和age,然后创建几个Person对象,
    将其添加到一个数组中,遍历数组,并打印未成年人的信息
*/

class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}


const personArr = [
    new Person("孙悟空", 18),
    new Person("沙和尚", 38),
    new Person("红孩儿", 8),
]


for(let i=0; i<personArr.length; i++){
    if(personArr[i].age < 18){
        console.log(personArr[i])
    }
}

>for-of语句

for-of 可以用来遍历迭代对象

语法:
    for(变量 of 可迭代的对象){
        语句...
    }

执行流程:
    for-of的循环体会执行多次,数组中有几个元素就会执行几次,
    每次执行时都会将一个元素赋值给变量


const arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]

for(let value of arr){
    console.log(value)
}

for(let value of "welcome"){
    console.log(value)
}

>数组的方法(非破坏性)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

/*
    Array.isArray()
        - 用来检查一个对象是否是数组    
*/
 console.log(Array.isArray({ name: "孙悟空" })) // false
 console.log(Array.isArray([1, 2, 3])) // true
/*
    at()
        - 可以根据索引获取数组中的指定元素
        - at可以接收负索引作为参数
*/

 const arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]
 console.log(arr.at(-2))
  • arr.at(-2)使用了数组的 at() 方法,它允许你通过索引来获取数组中的元素。

  • 在这个例子中,索引是 -2。at() 方法中的负索引表示从数组末尾开始计数。

  • 因此,arr.at(-2) 将获取数组中倒数第二个元素。 对于数组 ["孙悟空", "猪八戒", "沙和尚", "唐僧"],倒数第二个元素是 "沙和尚"。

  • 所以,这行代码将在控制台输出"沙和尚"

console.log(arr[arr.length - 2])
  • arr[arr.length - 2] 使用了标准的数组索引方式来获取元素。

  • arr.length 返回数组的长度,对于这个数组是 4

  • arr.length - 2 计算得到 2,这是数组中倒数第二个元素的索引。

  • 因此,arr[arr.length - 2] 将获取数组中索引为 2 的元素,即 "沙和尚"

  • 所以,这行代码也将在控制台输出 "沙和尚"

/* 
    concat()
        - 用来连接两个或多个数组
        - 非破坏性方法,不会影响原数组,而是返回一个新的数组
*/

const arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]
const arr2 = ["白骨精", "蜘蛛精", "玉兔精"]

let result = arr.concat(arr2, ["牛魔王","铁扇公主"])

console.log(result) 
// 输出:["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精", "蜘蛛精", "玉兔精", "牛魔王", "铁扇公主"]
  • const arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]; 定义了一个包含四个字符串元素的数组 arr

  • const arr2 = ["白骨精", "蜘蛛精", "玉兔精"]; 定义了另一个包含三个字符串元素的数组 arr2

  • let result = arr.concat(arr2, ["牛魔王","铁扇公主"]); 使用 concat() 方法合并数组 arrarr2 和一个新数组 ["牛魔王","铁扇公主"]concat() 方法不会改变原有的数组,而是返回一个新的数组,这个新数组包含了所有合并的元素。合并后的数组被赋值给变量 result

  • console.log(result); 打印变量 result 的值,也就是合并后的新数组。

/*
    indexOf()
        - 获取元素在数组中第一次出现的索引
        - 参数:
            1. 要查询的元素
            2. 查询的其实位置

    lastIndexOf()
        - 获取元素在数组中最后一次出现的位置

        - 返回值:
            找到了则返回元素的索引,
            没有找到返回-1
*/

console.log(result) 
// 输出:["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精", "蜘蛛精", "玉兔精", "牛魔王", "铁扇公主"]
let result = arr.indexOf("沙和尚", 3)
  • indexOf() 方法用于查找元素在数组中首次出现的位置。

  • 它接收两个参数:要查找的元素和(可选的)搜索的起始位置。

  • 在这个例子中,我们从索引 3 开始搜索 "沙和尚" 在数组 arr 中的位置。

  • 因为 "沙和尚" 在数组 arr 中的索引是 2,而 2 小于 3,所以 indexOf() 方法会返回 -1,表示未找到。

console.log(result) 
// 输出:["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精", "蜘蛛精", "玉兔精", "牛魔王", "铁扇公主"]
result = arr.lastIndexOf("沙和尚", 3)
  • lastIndexOf() 方法用于查找元素在数组中最后一次出现的位置。

  • 它同样接收两个参数:要查找的元素和(可选的)搜索的起始位置。

  • 在这个例子中,我们从索引 3 开始向前搜索 "沙和尚" 在数组 arr 中的最后一次出现的位置。

  • 因为 "沙和尚" 在数组 arr 中的索引是 2,而 2 小于等于 3,所以 lastIndexOf() 方法会返回 2。

console.log(result) 
// 输出:["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精", "蜘蛛精", "玉兔精", "牛魔王", "铁扇公主"]
result = arr.indexOf("白骨精")
  • 这里的 indexOf() 方法查找 "白骨精" 在数组 arr 中首次出现的位置。

  • 因为 "白骨精" 不在数组 arr 中,所以 indexOf() 方法会返回 -1。

/*
    join()
        - 将一个数组中的元素连接为一个字符串
        - ["孙悟空", "猪八戒", "沙和尚", "唐僧", "沙和尚"] -> "孙悟空,猪八戒,沙和尚,唐僧,沙和尚"
        - 参数:
            指定一个字符串作为连接符
*/
result = arr.join()
result = arr.join("@-@")
result = arr.join("")
/*
   slice()
        - 用来截取数组(非破坏性方法)     
        - 参数:
            1. 截取的起始位置(包括该位置)
            2. 截取的结束位置(不包括该位置)   
                - 第二个参数可以省略不写,如果省略则会一直截取到最后
                - 索引可以是负值

            如果将两个参数全都省略,则可以对数组进行浅拷贝(浅复制)
*/
arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]
result = arr.slice(0, 2) //输出: ["孙悟空", "猪八戒"]
result = arr.slice(1, 3)
result = arr.slice(1, -1)
result = arr.slice()
  • result = arr.slice(0, 2);

    • 这行代码从索引 0 开始提取,直到索引 2(不包括)为止。

    • 因此,它将返回数组中的前两个元素:["孙悟空", "猪八戒"]

  • result = arr.slice(1, 3);

    • 这行代码从索引 1 开始提取,直到索引 3(不包括)为止。

    • 因此,它将返回数组中的第二和第三个元素:["猪八戒", "沙和尚"]

  • result = arr.slice(1, -1);

    • 这行代码从索引 1 开始提取,直到数组倒数第一个元素(不包括)为止。

    • 因此,它将返回数组中除最后一个元素外的所有元素:["猪八戒", "沙和尚", "唐僧"]

  • result = arr.slice();

    • 当不提供任何参数时,slice() 方法将返回数组的一个浅拷贝。

    • 因此,它将返回原数组的一个副本:["孙悟空", "猪八戒", "沙和尚", "唐僧"]

>数组的复制

  • xx.slice() ==> 数组

  • Object.assign ==> 对象

const arr = ["孙悟空", "猪八戒", "沙和尚"]
// const arr2 = arr  // 不是复制
// arr2[0] = "唐僧" // 如此修改,在此打印时会显示["唐僧", "猪八戒", "沙和尚"],且全局更改

// 如何去复制一个对象 复制必须要产生新的对象
// 当调用slice时,会产生一个新的数组对象,从而完成对数组的复制
const arr3 = arr.slice()


// console.log(arr === arr2) 
// console.log(arr2)

arr3[0] = "唐僧"

console.log(arr) // 输出:["孙悟空", "猪八戒", "沙和尚"]
console.log(arr3) // 输出:["唐僧", "猪八戒", "沙和尚"]
/* 
    浅拷贝(shallow copy)
        - 通常对对象的拷贝都是浅拷贝
        - 浅拷贝顾名思义,只对对象的浅层进行复制(只复制一层)
        - 如果对象中存储的数据是原始值,那么拷贝的深浅是不重要
        - 浅拷贝只会对对象本身进行复制,不会复制对象中的属性(或元素)
*/

// 创建一个数组
const arr = [{name:"孙悟空"}, {name:"猪八戒"}] // 数组里的元素为对象
const arr2 = arr.slice() // 浅拷贝
console.log(arr)

/*
    深拷贝(deep copy)
        - 深拷贝指不仅复制对象本身,还复制对象中的属性和元素
        - 因为性能问题,通常情况不太使用深拷贝
*/

const arr3 = structuredClone(arr) // 专门用来深拷贝的方法
console.log(arr3)
const arr = ["孙悟空", "猪八戒", "沙和尚"]

const arr2 = arr.slice()

console.log(arr === arr2) // false

/* 
    ... (展开运算符)
        - 可以将一个数组中的元素展开到另一个数组中或者作为函数的参数传递
        - 通过它也可以对数组进行浅复制
*/

// const arr3 = [arr[0], arr[1], arr[2]] 等价于 const arr3 = [...arr]

const arr3 = [...arr]
// console.log(arr) // ["孙悟空", "猪八戒", "沙和尚"]

const arr3 = ["唐僧", ...arr, "白骨精"]
// console.log(arr3)  // ["唐僧", "孙悟空", "猪八戒", "沙和尚", "白骨精"]

/*
function 关键字用于定义函数。在你的代码中,sum 函数接受三个参数 a, b, 和 c,并返回它们的和。
定义了一个数组 arr4,包含三个元素:10, 20, 和 30。

用两种方式调用 sum 函数:

直接传递数组的元素作为参数:sum(arr4[0], arr4[1], arr4[2])。这种方式结果是 60。

使用扩展运算符传递数组中的所有元素:sum(...arr4)。这种方式也是将数组中的元素作为单独的参数传递给函数,结果同样是 60。
*/

function sum(a, b, c) {
    return a + b + c
}

const arr4 = [10, 20, 30]

let result = sum(arr4[0], arr4[1], arr4[2])

    result = sum(...arr4)

// console.log(result)


/* 
    对象的复制
        - Object.assign(目标对象, 被复制的对象)
        - 将被复制对象中的属性复制到目标对象里,并将目标对象返回

    - 也可以使用展开运算符对对象进行复制
*/

const obj = { name: "孙悟空", age: 18 }

// const obj2 = Object.assign({}, obj)
const obj2 = { address: "花果山", age: 28 } // 后复制的优先替换先前的,比如 age

Object.assign(obj2, obj)
// console.log(obj2)  // 输出: { address: "花果山", name: "孙悟空", age: 18 }

const obj3 = { address: "高老庄", ...obj, age: 48 } // 将obj中的属性在新对象中展开
// 输出: { address: "高老庄", name: "孙悟空", age: 48 }

>数组的方法(破坏性)

push()
    - 向数组的末尾添加一个或多个元素,并返回新的长度

let arr = ["孙悟空", "猪八戒", "沙和尚"]
let result = arr.push("唐僧", "白骨精")
console.log(result); // 输出:5
  • let arr = ["孙悟空", "猪八戒", "沙和尚"]; 定义了一个包含三个字符串元素的数组 arr

  • let result = arr.push("唐僧", "白骨精"); 调用了 push() 方法,向数组 arr 的末尾添加了两个新的元素:"唐僧" 和 "白骨精"。

    • push() 方法会返回更新后数组的长度。

    • 在这个例子中,push() 方法将返回 5,因为添加新元素后数组 arr 的长度变成了 5。

  • 变量 result 将被赋值为 5,这是更新后数组 arr 的长度。

pop()
    - 删除并返回数组的最后一个元素

let arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]
result = arr.pop() // 输出:"白骨精"
  • result = arr.pop(); 调用了 pop() 方法,它会删除数组 arr 的最后一个元素,并将其值赋给变量 result

    • pop() 方法会改变原数组,减少其长度。

    • 在这个例子中,如果 arr 的初始状态如上所述,pop() 方法将删除 "白骨精" 并返回它。

  • 变量 result 将被赋值为 "白骨精",这是原数组 arr 被删除的最后一个元素。

unshift()
    - 向数组的开头添加一个或多个元素,并返回新的长度

let arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]
arr.unshift("牛魔王")
console.log(arr) // 输出: ["牛魔王","孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]


shift()
    - 删除并返回数组的第一个元素

arr.shift() //输出: “牛魔王”
console.log(arr) // 输出: ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"]
splice()
    - 可以删除、插入、替换数组中的元素
    - 参数:
        1. 删除的起始位置
        2. 删除的数量
        3. 要插入的元素

    - 返回值:
        - 返回被删除的元素

let arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧"]
console.log(arr) //输出: ['孙悟空']

result = arr.splice(1, 3) //输出:["猪八戒", "沙和尚", "唐僧"]
//将删除的元素赋值给 result 

result = arr.splice(1,2,'牛魔王')
console.log(result); // 输出:["猪八戒", "沙和尚"]
console.log(arr);    // 输出:["孙悟空", "牛魔王", "唐僧"]
  • arr.splice(1, 2, '牛魔王') 调用了 splice() 方法,它接收至少两个参数:

    • 第一个参数 1 是开始修改的索引位置。

    • 第二个参数 2 是要删除的元素数量。

    • 第三个参数 '牛魔王' 是要添加进数组的元素,它会在删除元素的位置之后插入。

  • splice() 方法会改变原数组,并返回一个包含被删除元素的新数组。

  • 在这个例子中,从索引 1 开始,删除 2 个元素(即 "猪八戒" 和 "沙和尚"),然后在相同的位置插入 '牛魔王'

  • 变量 result 将被赋值为 ["猪八戒", "沙和尚"],这是被删除的元素组成的数组。

执行这段代码后,原数组 arr 将变为 ["孙悟空", "牛魔王", "唐僧"],并且变量 result 的值是 ["猪八戒", "沙和尚"]

 result = arr.splice(1, 0, "牛魔王", "铁扇公主", "红孩儿")
  • arr.splice(1, 0, "牛魔王", "铁扇公主", "红孩儿") 调用了 splice() 方法,它接收至少两个参数:

    • 第一个参数 1 是开始修改的索引位置。

    • 第二个参数 0 是要删除的元素数量。

    • 后续的参数("牛魔王", "铁扇公主", "红孩儿")是要添加进数组的元素,它们会在删除元素的位置之后插入。

  • splice() 方法会改变原数组,并返回一个包含被删除元素的新数组。

  • 在这个例子中,从索引 1 开始,我们不删除任何元素(删除数量为 0),然后在相同的位置插入 "牛魔王", "铁扇公主", "红孩儿" 这三个元素。

  • 变量 result 将被赋值为 [],因为没有任何元素被删除。

执行这段代码后,原数组 arr 将变为 ["孙悟空", "牛魔王", "铁扇公主", "红孩儿", "猪八戒", "沙和尚", "唐僧"],并且变量 result 的值是 [](空数组)。

reverse()
    - 反转数组

let arr = ["a", "b", "c", "d"]
arr.reverse() //输出:['d', 'c', 'b', 'a']

>数组的去重

有如下一个数组arr = [1,2,1,3,2,4,5,5,6,7],编写代码,去除数组中重复的元素。

// 定义一个包含重复数字的数组
const arr = [1, 2, 1, 3, 2, 2, 4, 5, 5, 6, 7];

// 外层循环:遍历数组中的每个元素
for (let i = 0; i < arr.length; i++) {
    // 内层循环:从当前元素的下一个元素开始,检查后面的所有元素
    for (let j = i + 1; j < arr.length; j++) {
        // 如果发现外层循环的元素与内层循环的元素相等,说明找到了一个重复的元素
        if (arr[i] === arr[j]) {
            // 使用 splice 方法删除重复的元素
            arr.splice(j, 1);
            // 因为删除了一个元素,后面的元素会向前移动一位,所以需要将 j 退回一位,以确保不会漏掉任何一个元素
            j--;
        }
    }
}

// 打印处理后的数组,此时数组中不再包含重复的元素
console.log(arr); // 输出:[1, 2, 3, 4, 5, 6, 7]
// 定义一个包含重复数字的数组
const arr = [1, 2, 1, 3, 2, 2, 4, 5, 5, 6, 7];

// 遍历数组中的每个元素
for (let i = 0; i < arr.length; i++) {
    // 查找当前元素在数组中从当前位置之后的第一次出现的位置
    const index = arr.indexOf(arr[i], i + 1);
    // 如果找到了重复元素(index不等于空值)
    if (index !== -1) {
        // 删除数组中该重复元素
        arr.splice(index, 1);
        // 由于删除了一个元素,数组的长度减少,需要调整循环变量以避免跳过元素
        i--;
    }
}

// 打印处理后的数组,此时数组中不再包含重复的元素
console.log(arr); // 输出:[1, 2, 3, 4, 5, 6, 7]
// 定义一个包含重复数字的数组
const arr = [1, 2, 1, 3, 2, 2, 4, 5, 5, 6, 7];

// 创建一个空数组,用于存储非重复的元素
const newArr = [];

// 遍历原始数组中的每个元素
for (let ele of arr) {
    // 检查当前元素是否已经在 newArr 中
    if (newArr.indexOf(ele) === -1) {
        // 如果当前元素不在 newArr 中,则将其添加到 newArr
        newArr.push(ele);
    }
}

// 打印包含非重复元素的新数组
console.log(newArr); // 输出:[1, 2, 3, 4, 5, 6, 7]

>冒泡排序

9, 1, 3, 2, 8, 0, 5, 7, 6, 4

- 比较相邻的两个元素,然后根据大小来决定是否交换它们的位置
- 例子:
    第一次排序:1, 3, 2, 8, 0, 5, 7, 6, 4, 9
    第二次排序:1, 2, 3, 0, 5, 7, 6, 4, 8, 9
    第三次排序:1, 2, 0, 3, 5, 6, 4, 7, 8, 9
    ...
    倒数第二次 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

const arr = [9, 1, 3, 2, 8, 0, 5, 7, 6, 4]

/*
for (let j = 0; j < arr.length - 1; j++) {
    for (let i = 0; i < arr.length - 1; i++) {
        // arr[i] 前边的元素 arr[i+1] 后边元素
        if (arr[i] < arr[i + 1]) {
            // 大数在前,小数在后,需要交换两个元素的位置
            let temp = arr[i] // 临时变量用来存储arr[i]的值
            arr[i] = arr[i + 1] // 将arr[i+1]的值赋给arr[i]
            arr[i + 1] = temp // 修改arr[i+1]的值
        }
    }
}
*/
优化代码:
for (let j = 0; j < arr.length - 1; j++) {
    for (let i = 0; i < arr.length - 1 - j; i++) {
        // arr[i] 前边的元素 arr[i+1] 后边元素
        if (arr[i] < arr[i + 1]) {
            // 大数在前,小数在后,需要交换两个元素的位置
            let temp = arr[i] // 临时变量用来存储arr[i]的值
            arr[i] = arr[i + 1] // 将arr[i+1]的值赋给arr[i]
            arr[i + 1] = temp // 修改arr[i+1]的值
        }
    }
}
console.log(arr)

- 这种排序方式,被称为冒泡排序,冒泡排序是最慢的排序方式,
  数字少还可以凑合用,不适用于数据量较大的排序

>选择排序

- 取出一个元素,然后将其他元素和该元素进行比较,如果其他元素比该元素小则交换两个元素的位置
- 例子:
    第一次排序:0, 9, 3, 2, 8, 1, 5, 7, 6, 4
    第二次排序:0, 1, 9, 3, 8, 2, 5, 7, 6, 4
    第二次排序:0, 1, 2, 9, 8, 3, 5, 7, 6, 4
    ...

console.log(arr)

// 遍历原始数组中的每个元素
for(let i=0; i<arr.length; i++){
    for(let j=i+1; j<arr.length; j++){
        if(arr[i] > arr[j]){
            // 交换两个元素的位置
            let temp = arr[i] // 临时变量用来存储arr[i]的值
            arr[i] = arr[j] // 将arr[i]的值赋给arr[j]
            arr[j] = temp   // 修改arr[j]的值
        }
        }
    }
}

console.log(arr)

  选择排序
    - 取出一个元素,然后将其他元素和该元素进行比较,如果其他元素比该元素小则交换两个元素的位置

>封装函数

const arr = [9, 1, 3, 2, 8, 0, 5, 7, 6, 4]
const arr2 = [9, 8, 7, 6, 5, 4, 3, 2, 1]

function sort(array) {
    const arr = [...array]
    for (let i = 0; i < arr.length; i++) {
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[i] > arr[j]) {
                // 交换两个元素的位置
                let temp = arr[i]
                arr[i] = arr[j]
                arr[j] = temp
            }
        }
    }
    return arr
}

let result = sort(arr2)

// console.log(arr2)
// console.log(result)
class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

const personArr = [
    new Person("孙悟空", 18),
    new Person("沙和尚", 38),
    new Person("红孩儿", 8),
    new Person("白骨精", 16),
]


// filter()函数用来对数组进行过滤
function filter(arr) {

    const newArr = []

    for (let i = 0; i < arr.length; i++) {
        if (arr[i].age < 18) {
            newArr.push(arr[i])
        }
    }

    return newArr
}

result = filter(personArr)
console.log(result)


- - - - - - - - - - - - - - - - - 

目前我们的函数只能过滤出数组中age属性小于18的对象,
    - 我们希望过滤更加灵活:
        比如:过滤数组中age大于18的对象
             过滤数组中age大于60的对象
             过滤数组中age大于n的对象
             过滤数组中name为xxx的对象
             过滤数组中的偶数
             ...

>回调函数

如果将函数作为参数传递,那么我们就称这个函数为回调函数(callback)

请注意!一个函数的参数也可以是函数

class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}

const personArr = [
    new Person("孙悟空", 18),
    new Person("沙和尚", 38),
    new Person("红孩儿", 8),
    new Person("白骨精", 16),

function filter(arr, cb) {
    const newArr = []  // 创建一个空数组用于存放符合条件的元素

    //遍历并获取里面的元素
    for (let i = 0; i < arr.length; i++) {
          
         // 当前数组元素 arr[i] 的 name 是否等于 '孙悟空'?”
        if (cb(arr[i])) {  // 这里的 cb 实际上就是 fn

        // 如果是 true(即当前元素符合条件),则将这个元素添加到结果数组中
            newArr.push(arr[i])  // 将符合条件的元素加入 newArr
        }
    }

    return newArr  // 返回新数组
}


function fn(a) {
    return a.name === "孙悟空" // a.name 是数组元素的 name 属性
}

// 调用 filter 函数,传递 personArr 数组和回调函数 fn 作为参数
let result = filter(personArr, fn)

// 打印 filter 函数的返回值,即满足条件的元素组成的数组
console.log(result)