八十九——一三三

八十九、JavaScript——数组的简介

一、数组

数组(Array)

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

                - 数组中存储的是有序的数据,数组中的每个数据有一个唯一的索引

                    可以通过索引来操作获取数据

                - 数据中存储的数据叫元素

                - 索引(index)是一组大于0的整数

                - 创建数组

                    1. 通过Array()来创建数组

                        语法:

                            const 数组名 = new Array()

                    2. 通过中括号创建数组

                        语法:

                            const 数组名 = []


 

                - 向数组中添加元素

                    语法:

                        数组[索引值] = 元素

                       

                - 读取数组中的元素

                    语法:

                        数组[索引]

                        - 如果读取了一个不存在的元素,不会报错而是返回undefined

                        - 用typeof检查数组,返回为 object


 

                - 获取数组元素的长度

                    语法:

                        数组名.length

                        - 获取数组的长度

                        - 获取的实际值就是数组的 最大索引 + 1

                       

                - 向数组的最后添加元素

                    语法:

                        数组[数组.length] = 元素

                - 修改数组的长度

                    数组名.length = 长度值

- 创建数组

                 通过Array()来创建数组,也可以通过中括号创建数组

                - 向数组中添加元素

                    语法:

                        数组[索引值] = 元素

 // 创建数组方式一:调用 Array() 来创建数组
        const arr = new Array()

        // 创建数组方式二:通过 中括号[] 创建数组
        const arr2 = []  // 数组字面量

 用typeof检查数组,返回为 object

// 使用 typeof检查数组数据类型时,返回object
        console.log(typeof arr)

 

  <script>
        /*
            数组(Array)
                - 数组也是一中复合数据类型,在数组可以存储多个不同类型的数据
                - 数组中存储的是有序的数据,数组中的每个数据有一个唯一的索引
                    可以通过索引来操作获取数据
                - 数据中存储的数据叫元素
                - 索引(index)是一组大于0的整数

                - 创建数组
                    1. 通过Array()来创建数组
                        语法:
                            const 数组名 = new Array()
                    2. 通过中括号创建数组
                        语法:
                            const 数组名 = []


                - 向数组中添加元素
                    语法:
                        数组[索引值] = 元素
                        

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


                - 获取数组元素的长度
                    语法:
                        数组名.length
                        - 获取数组的长度
                        - 获取的实际值就是数组的 最大索引 + 1
                        
                - 向数组的最后添加元素
                    语法:
                        数组[数组.length] = 元素

                - 修改数组的长度
                    数组名.length = 长度值


                
        */

        // 创建数组方式一:调用 Array() 来创建数组
        const arr = new Array()

        // 创建数组方式二:通过 中括号[] 创建数组
        const arr2 = []  // 数组字面量


        // 向数组中索引为0的位置添加值10
        arr[0] = 10
       
        // 跳过中间一段索引,直接向后面的索引位置添加值
        // 使用数组时,应避免非连续数组,因为它性能不好
        arr[100] = 99

        console.log(arr)
        console.log(arr2)

        // 使用 typeof检查数组数据类型时,返回object
        console.log(typeof arr)

        // 获取数组的长度
        console.log(arr.length)


        // 修改数组的长度,没有值的部分显示空属性
        arr.length = 11;



    </script>

九十、JavaScript——数组的遍历

 /*
            遍历数组
                - 获取数组中的每一个元素
        */

        const arr1 = ["甲", "乙", "丙", "丁"]

        // for循环遍历数组
        for(let i=0; i<arr.length; i++){

            console.log(arr[i])
        }

 <script>
        /*
            1. 创建数组, 任何类型都可以成为数组中的对象
            2. 创建数组时尽量保证数组中存储的数据类型时相同的,方便操作
        */
        // 创建数组, 任何类型都可以成为数组中的对象
        const arr = [1, 2, "hello", true,  ]

        /*
            遍历数组
                - 获取数组中的每一个元素
        */

        const arr1 = ["甲", "乙", "丙", "丁"]

        // for循环遍历数组
        for(let i=0; i<arr.length; i++){

            console.log(arr[i])
        }

        /*
            定义一个Person类,类中由两个属性name和age
                然后创建几个Person对象,将其添加到一个数组中

            遍历数组,打印未成年人信息

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

       const personArr = [new Person("张三", 19),
                          new Person("李四", 22),
                          new Person("王五", 9),]

         for(let i=0; i<personArr.length; i++){

            console.log(personArr[i])

            if (personArr[i].age < 18){

                console.log("未成年人的信息为" + personArr[i])
            }
            
        }                

    </script>

 九十一、JavaScript——for-of语句

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

            语法:

                for(变量 of 可迭代的对象){

                    语句...         }


    <script>

        /*
            for-of语句可以用来遍历可迭代对象

            语法:
                for(变量 of 可迭代的对象){
                    语句...
                }
            执行流程:
                for-of的循环体会执行多次,数组中有几个元素就会执行几次
                    每一次执行都会把一个元素赋值给变量 
        */

        const arr1 = ["甲", "乙", "丙", "丁"]

        // 每一次遍历都将值赋值给了 变量value
        for(let value of arr1){
            
            console.log(value)
        }

    </script>

 

  九十二、JavaScript——数组方法介绍

<script>
        /*
                MDN网站中关于数组的介绍:
                            https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array

                
                举例:
                            静态方法:Array.isArray()
                            如果参数是数组则返回 true ,否则返回 false 

                            实例方法:Array.prototype.at()   类.对象.at()
                            数组的索引值接收负数,即从后往前数

                
        */

        // 利用静态方法 Array.isArray() 判断参数是否是一个数组
        console.log(Array.isArray({ name: "孙悟空"}))  // false 参数是对象不是数组
        console.log(Array.isArray([1, 2, 3]))  // true 参数是数组

        // Array.prototype.at() 接收负数的索引值,从后往前索引数组值
        const arr = [1, 2, "hello", "aaaa"  ]

        console.log(arr.at(-1))  // 打印结果为数组的倒数第一个值 -1

    </script>

 九十三、JavaScript——数组方法介绍

join()

                - 将一个数组中的元素连接为一个字符串

                语法:

                    数组名.join("指定字符串为连接符")

                   

                举例:["甲", "乙", "丙", "丁"]  -- > "甲, 乙, 丙, 丁"

 const arr1 = ["甲", "乙", "丙", "丁"]
// join("指定某字符作为连接符") 
        let resu = arr1.join("@")
        console.log(resu)

 <script>
        /*
            indexOf()
                - 从前往后查询
                - 获取元素在数组中第一次出现的位置索引
                - 参数:
                    1. 要查询的元素
                    2. 查询的真实位置
                    arr.indexOf(查询的元素 , 从下标为某处的地方处开始查)

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

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


            join()
                - 将一个数组中的元素连接为一个字符串
                语法: 
                    数组名.join("指定字符串为连接符")

                    
                举例:["甲", "乙", "丙", "丁"]  -- > "甲, 乙, 丙, 丁"


            slice()
                - 用来获取数据(非破坏性方法)
                语法:
                    -数组名.slice( 截取的起始位置(包括该位置), 截取的结束位置(不包括该位置) )
                    第二个参数可以省略不写,如果省略则会一直截取到最后\

                    如果两个参数全部省略,可以进行浅复制

        */

        const arr1 = ["甲", "乙", "丙", "丁"]
        // arr.indexOf(查询丙的位置 , 从下标为2处开始查) 
        let result = arr1.indexOf("丁", 1)   // 结果为3
        console.log(result)

        let res = arr1.lastIndexOf("丙")    // 结果为2
        console.log(res)

        // join("指定某字符作为连接符") 
        let resu = arr1.join("@")
        console.log(resu)

        let resul = arr1.slice(0, 2)
        console.log(resul)

    </script>

 九十四、JavaScript——对象的复制

  <script>
        const arr = ["甲", "乙", "丙", "丁"]

        // 如何去复制一个对象,复制一定会产生一个新的对象
        // 当调用slice时,会产生一个新的数组对象,从而完成对数组的复制
        const arr3 = arr.slice()
        arr3[0] = "A"
        console.log(arr)
        console.log(arr3)


        // 不能称为复制,arr2和arr1指向的时同一个对象地址
        // const arr2 = arr1  


    </script>

 九十五、JavaScript——深拷贝与浅拷贝

一、浅拷贝

浅拷贝(shallow copy)

                - 通常对对象的拷贝都是浅拷贝

                - 浅拷贝顾名思义,只对对象的浅层进行复制(只复制一层)

                -  如果对象中存储的数据是原始值,那么拷贝的深浅不重要

                    - ["甲", "乙", "丙", "丁"] 中的 甲,乙,丙,丁 就是原始值

                - 浅拷贝只会对对象本身进行复制,不会复制对象中的属性(元素)

  // 创建一个数组
        const arr = [ {name: "孙悟空"}, {name: "猪八戒"}]

        // 利用slice()进行浅拷贝
        const arr2 = arr.slice()

 

 

二、深拷贝

 深拷贝(deep copy)

                - 深拷贝指不仅复制对象本身,还复制对象中的属性和元素

                - 因为性能问题,通常情况下不使用深拷贝

                语法:

                    structuredClone(拷贝对象)


        // 创建一个数组
        const arr = [ {name: "孙悟空"}, {name: "猪八戒"}]

      

        // structuredClone(拷贝对象)  专门用来深拷贝的方法
        const arr3 = structuredClone(arr)

  九十六、JavaScript——复制的方式

 ...(展开运算符)

                - 可以将一个数组中的元素展开到另一个数组中或者作为函数的参数传递

                - 通过它可以对数组进行浅拷贝

一、利用展开运算符进行复制


        // 复制的方式一
        const arr3 = [arr[0], arr[1], arr[2]]

        // 复制的方式二:利用...展开运算符进行复制
        const arr4 = [...arr]

        console.log( arr ) 
        console.log( arr4 )  
        console.log( arr === arr4)  // false, arr和arr4虽然是复制的得来,但并不相等

二、数组的复制


        // 数组的复制 需要传递多个参数时可以使用展开运算符
        function sum(a, b, c, d){
            return a + b + c + d
        }

        const arr5 = [10, 20, 20, 10,10]
        
        let result = sum(...arr5)   // 使用展开运算符,将多个参数传入

        console.log(result)

 三、对象的复制

            对象的复制

                - 方式一通过类调用的静态方法

                    - Object.assign(目标对象, 被复制的对象)

                    - 将被复制对象中的属性复制到目标对象里,并将目标对象返回

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

 const obj = {name: "张三", age: 11}

        const obj3 = {name: "李四", age: 88}

        // assign({}, obj)  将后面的obj对象复制给前面的{} ,再将结果赋值给obj2
        const obj2 = Object.assign({}, obj)

        console.log(obj2 === obj)

      const obj = {name: "张三", age: 11}

        const obj3 = {name: "李四", age: 88}

        // 后面的obj会覆盖前面的obj3的内容
        Object.assign( obj3, obj)

        console.log(obj3)
        
        console.log(obj3 === obj)

 


        // 展开运算符 ,重复属性的位置决定了最终的显示结果

        // 重复属性age 在展开运算符前,结果显示展开运算符中的内容
        const obj4 = { address: "地点A", age: 22, ...obj}   // age最终显示11

        console.log(obj4)

        // 重复属性age 在展开运算符后,结果显示重复属性中的内容
        const obj5 = { address: "地点A",  ...obj, age: 22}   // age 最终显示22
        
        console.log(obj5)

 

 九十七、JavaScript——数组的方法

 push()

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

 pop()

    - 删除数组中的最后一位元素,并返回数组被删除的那个元素

 unshift()

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

  shift()

   - 删除数组中的第一位元素,并返回数组被删除的那个元素

const arr = ["甲", "乙", "丙", "丁"]

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

        arr.push("赵", "钱")
        //  打印结果为["甲", "乙", "丙", "丁", "赵", "钱"]
        console.log(arr)
        

        //  打印结果 6 即push后的数组长度
        let result = arr.push("赵", "钱")

        console.log(result)



        /*
            执行pop()方法
            - 删除数组中的最后一位元素,并返回数组被删除的那个元素
        */


        //  打印结果为["甲", "乙", "丙", "丁", "赵"],删除了数组最后一位元素
        arr.pop()

        //  打印结果 "钱" 删除了谁就打印谁
        let res = arr.pop()

        console.log(res)


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

        //  打印结果为["开头", "甲", "乙", "丙", "丁", "赵"]
       arr.unshift("开头")

       //  打印结果 8 即unshift后的数组长度
       let re = arr.unshift("开头")

       console.log(re)



         /*
            shift()
                - 删除数组中的第一位元素,并返回数组被删除的那个元素
        */

        arr.shift()

        //  打印结果 "开头" 删除了谁就打印谁
        let ress = arr.shift()

        console.log(ress)

 splice()

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

            - 可以删除、插入、替换数组中的元素

                - 参数:

                    1. 删除的起始位置

                    2. 删除的数量

                   

                - 返回值

                    - 返回被删除的元素

 reverse()

                - 反转数组

            删除

                - splice(删除的起始位置, 删除的数量)

           

            替换  

                - splice(删除的起始位置, 删除的数量, "元素一", "元素二")

                    - 在删除的起始位置处插入元素一,元素二

            插入

                - splice(删除的起始位置, 0 )

                    - 删除0个元素,在删除的起始位置插入元素

  // 从数组下标为1开始删除,删除的数量为3
        ass = arr.splice(1, 3) 

        // 从数组下标为1开始删除,删除的数量为1,插入'A' 'B'
        ress = arr.splice(1, 1, "A", "B")

        // 从数组下标为1开始删除,删除的数量为0, 插入'A' 'B'
        resss = arr.splice(1, 0, "C", "D")

        const arrsss = ["a", "b", "c", "d"]

        // 反转数组
        arrsss.reverse()  // 输出 ["d", "c", "b", "a"]

九十八、JavaScript——数组的去重

法一:利用两次for循环完成数组的去重

  <script>

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

    // 编写代码去除数组中重复的代码

    // 分别获取数组的元素
    for(let i=0; i<arr.length; i++){
        
        console.log(arr[i])
        
        // 获取当前值后边的所有值
        for(let j=i+1; j<arr.length; j++ ){
            console.log(arr[j])

            // 判断两个数是否相同
            if(arr[i] === arr[j]){

                // 出现了重复元素,删除后边的元素
                arr.splice(j,1)

                /*
                    arr[i] 和 arr[j]相同时,它会自动删除j位置的元素,然后j+1位置的元素,会自动变成
                    j位置的元素,而j位置的元素已经比较过了,不会重复比较,所以会出现漏比较的情况

                    解决办法:当删除一个元素后,需要将该位置的元素再比较一遍
                */

                // 将j的位置向前移,保证可以再比较一遍
                j--
            }
        }
    }

    console.log(arr)

  

    </script>

 法二:利用 indexof 进行比较再利用 splice 完成数组的去重

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

        // 获取数组中的元素
        for(let i=0; i<arr.length; i++){
            // indexof和instanceOf,数组中含有元素与某对象是否是某类
            // 从i+1后面的位置开始找,与arr[i]做对比,返回一个结果
            const index = arr.indexOf(arr[i], i+1)

            if( index !== -1){
                // 出现重复内容,利用splice进行删除
                arr.splice(index, 1)

                // 当删除一个元素后,需要将该位置的元素再比较一遍
                i--
            }
        }

        console.log(arr)

法三:利用 for of 进行比较再利用 push 进行添加完成数组的去重

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

        // 创建一个空数组
        const newArr = []

        // 用for循环对数组进行遍历, ele表示数组中的元素
        for(let ele of arr){
            // 新的数组中,如果不包含这个元素,即不重复
            if(newArr.indexOf(ele) != -1){
                // 利用push添加
                newArr.push(ele)

            }
        }
        console.log(newArr)

一百、JavaScript——冒泡排序

   /*
            [9,1,3,2,8,0,5,7,6,4]

            思路一:
            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

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

            思路二:
            9, 1, 3, 2, 8, 0, 5, 7, 6, 4
            - 取出一个元素,然后将其他元素和该元素进行比较,如果其他元素比该元素小则交换两个元素的位置
            - 例子:
                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
                ...

            - 选择排序

                   
        */
       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 //将临时变量temp中的值赋值给arr[i+1]
            }
        
       }
        

       }
     
       console.log(arr)

一零一、JavaScript——选择排序

  <script>

      

        // 优化冒泡排序,内层循环使用 arr.length - 1 -j
        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 -j; i++) {
                if (arr[i] > arr[i + 1]) {
                    let temp = arr[i]
                    arr[i] = arr[i + 1]
                    arr[i + 1] = temp
                }
            }
        }

          /*
             9, 1, 3, 2, 8, 0, 5, 7, 6, 4
            - 取出一个元素,然后将其他元素和该元素进行比较,如果其他元素比该元素小则交换两个元素的位置
            - 例子:
                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
                ...

            - 选择排序
          
        */

        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
            }
             }
        }



    </script>

一零二、JavaScript——封装函数

将排序的方法封装成一个函数,进行调用


        /*
            将排序的方法封装成一个函数,进行调用
        */
        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)

将遍历的方法封装成一个函数,进行调用 

/*
            定义一个Person类,类中由两个属性name和age
                然后创建几个Person对象,将其添加到一个数组中

            遍历数组,打印未成年人信息

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

       const personArr = [new Person("张三", 19),
                          new Person("李四", 22),
                          new Person("王五", 9),
                        ]

         
        
        
        // 将遍历的方法封装成一个函数,
        function filter(arr){

            // 构建一个新的数组
            const newArr = []

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

            // 将添加完成的数组返回出来
            return newArr
        }

        // 将调用函数的结果用一个变量接收
        const index = filter(personArr)

        console.log(index)

回调函数:将函数作为参数传递

    <script>

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

       const personArr = [new Person("张三", 19),
                          new Person("李四", 22),
                          new Person("王五", 9),
                        ]

         
        
        
        // 将遍历的方法封装成一个函数,第二个参数是cb即回调函数,即将函数作为参数传递
        function filter(arr, cb){

            // 构建一个新的数组
            const newArr = []

            for(let i=0; i<arr.length; i++){

                // 3. 调用cb函数传入实参arr[i]
                if (cb(arr[i])){
                    newArr.push(arr[i])
                }
            }  

            // 将添加完成的数组返回出来
            return newArr
        }


        //1.  定义一个函数,
        function fn(a){
            // 2. 返回值返回所需的判定条件
            return a.age < 18
        }
        // 将调用函数的结果用一个变量接收
        // 传入的实参中,第二个实参传入的是一个函数
        const index = filter(personArr,fn)

        console.log(index)



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

                一个函数的参数也可以是函数
                    如果将函数作为参数传递,那么我们就称这个函数为回调(callback)
        */
        
    </script>

一零四、JavaScript——高阶函数

一、函数的参数是函数,则该函数是高阶函数

            高阶函数

                - 如果一个函数的参数或返回值是函数,则这个函数就是高阶函数

                - 为什么要将函数作为参数传递?(回调函数有什么作用?)

                    - 将函数作为参数,意味着可以对另一个函数动态传递代码

                   

                - 通常直接定义回调函数的形式比较少见,通常回调函数都是匿名函数

 <script>

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

       const personArr = [new Person("张三", 19),
                          new Person("李四", 22),
                          new Person("王五", 9),
                        ]

         
        
        /*
            高阶函数
                - 如果一个函数的参数或返回值是函数,则这个函数就是高阶函数
                - 为什么要将函数作为参数传递?(回调函数有什么作用)
                    - 将函数作为参数,意味着可以对另一个函数动态传递代码
                    
                - 通常直接定义回调函数的形式比较少见,通常回调函数都是匿名函数

        */
        
        // 将遍历的方法封装成一个函数,第二个参数是cb即回调函数,即将函数作为参数传递
        function filter(arr, cb){

            // 构建一个新的数组
            const newArr = []

            for(let i=0; i<arr.length; i++){

                // 3. 调用cb函数传入实参arr[i]
                if (cb(arr[i])){
                    newArr.push(arr[i])
                }
            }  

            // 将添加完成的数组返回出来
            return newArr
        }


        // 通常直接定义回调函数的形式比较少见,通常回调函数都是匿名

        //1.  定义一个函数,
        // function fn(a){
        //     // 2. 返回值返回所需的判定条件
        //     return a.age < 18
        // }



        // 将调用函数的结果用一个变量接收
        // 传入的实参中,第二个实参传入的是一个匿名函数
        const index = filter(personArr,a => a.name == "张三")

        const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        // 实参传入匿名函数,筛选出偶数
        const inde = filter(arr, a => a % 2 === 0)

        console.log(inde)

    </script>

二、函数作为返回值,该函数是高阶函数

    <script>
        /*
            希望在someFn()函数执行时,可以记录一条日志

            在不修改原函数的基础上,为其增加记录日志的功能
        */

        function someFn(){
            
            return "hello"
        }

        
        function outer(cb){

            return () => {

                console.log("记录日志---")
                const result = cb()
                return result
            }
        }

        // 调用函数的结果存储到一个返回值中
        let result = outer(someFn)

        // 通过result()调用someFn
        result()
    



        function test(){
            console.log("test-----")

            return "test"
        }

        
        // newTest具备了test全部功能同时还能打印记录日志
        let newTest = outer(test)

        // 通过newTest()调用test
        newTest()

    </script>

一零六、JavaScript——闭包简介

一、闭包简介

            闭包

                闭包就是能访问到外部函数作用域中变量的函数

            什么时候使用闭包:

                当我们要隐藏一些不希望被别人访问到的内容时我们就可以使用闭包

            构成闭包的条件:

                1.函数的嵌套

                2.内部函数要引用外部函数中的变量(例子中return返回的匿名函数对外部函数的num进行了引用)

                3.内部函数要作为返回值返回

<script>
        /*
            创建一个函数,第一次调用时打印1,第二次调用打印2,以此类推

            可以利用函数,来隐藏不希望被外界访问到的变量

            闭包:
                闭包就是能访问到外部函数作用域中变量的函数
            什么时候使用闭包:
                当我们要隐藏一些不希望被别人访问到的内容时我们就可以使用闭包
            构成闭包的条件:
                1.函数的嵌套
                2.内部函数要引用外部函数中的变量(例子中return返回的匿名函数对外部函数的num进行了引用)
                3.内部函数要作为返回值返回
        */


    // 将变量放到全局区只会定义一次
    //     let num = 0 

    //    function fn(){
        

    //     num++
    //     console.log(num)

    //    }

    //    fn()


    // 1.定义一个outer()函数
    function outer(){

        let num = 0 // 位于函数作用域内的变量

        // 2.返回一个匿名函数
        return () => {
            num++
            
        }
    }

    // 3.调用outer函数,将结果赋值给newFn
    const newFn = outer()

    // 4.调用newFn()
    newFn()


    </script>

 一零七、JavaScript——闭包的原理

  1. 函数在作用域,在函数创建时就已经确定,称之为词法作用域,与函数在哪调用无关
  2. 调用变量时,优先调用函数内部的局部变量,内部没有,再去函数外层找相关变量进行调用
  3. 闭包利用的就是词法作用域

调用函数时,访问变量的顺序是:先在函数内部查找是否有相关的局部变量进行访问,如果函数内部没有,再去函数外层访问相关的变量 

 <script>
        

        /*
            函数在作用域,在函数创建时就已经确定,称之为词法作用域
                与函数在哪调用无关
            调用变量时,优先调用函数内部的局部变量,内部没有,再去函数外层找相关变量进行调用
            闭包利用的就是词法作用域

        */
        let a = "全局变量a"

        function fn(){
            console.log(a)
        }

        fn()


        function fn2(){
            // fn2函数内部的局部变量a
            let a = "fn2中的a"

            // 调用fn() 访问的是fn的外层作用域中的变量a
            fn()
        }

        fn2()

        function fn3(){
            let a = "fn3中的a"

            function fn4(){

                console.log(a)
            
            }

            fn4()
        }

        // 调用fn3即调用了fn4,fn4定义的位置内部没有变量a,外层作用域的变量a被访问
        fn3()  // 打印输出"fn3中的a"



    </script>

 一零八、JavaScript——闭包的注意事项

闭包的生命周期:

  1. 闭包在外部函数调用时产生,外部函数每次的调用会产生一个权限的闭包
  2. 在内部函数丢失时销毁(内部函数被垃圾回收了,闭包才会消失

注意事项:

  • 闭包主要用来隐藏一些不希望被外界访问的内容
  • 这就意味着闭包要占用一定的内存空间
  •   相较于类来说,闭包比较浪费内存空间(类可以使用原型而闭包不能)
  •                     需要执行次数较少时,使用闭包

                        需要大量创建实例时,使用类      

<script>


        // 1.定义外部函数
        function outer(){
            // 2. 定义外层的变量
            let someVar = "外层变量"

            // 3. 将内部的匿名函数返回
            return function(){

                // 4.调用外层定义的变量
                console.log(someVar)

            }
        }

        // 5.调用外部函数
        outer()


        /*
            闭包的生命周期:
                1.闭包在外部函数调用时产生,外部函数每次的调用会产生一个权限的闭包
                2.在内部函数丢失时销毁(内部函数被垃圾回收了,闭包才会消失)

            注意事项:
                闭包主要用来隐藏一些不希望被外界访问的内容
                    这就意味着闭包要占用一定的内存空间
                相较于类来说,闭包比较浪费内存空间(类可以使用原型而闭包不能)
                    需要执行次数较少时,使用闭包
                    需要大量创建实例时,使用类


        */
    </script>

一零九、JavaScript——递归

            递归:

                - 调用自身的函数称为递归函数

                - 递归的作用和循环基本一致

            编写递归函数,一定要包含两个条件

                1.基线条件 —— 递归的终止条件

                2.递归条件 —— 如何对问题进行拆分

            递归的作用和循环是一致的,不同点在于,递归思路的比较清晰简介,循环的执行性能比较好

                在开发中,一般的问题都可以通过循环解决,也是尽量去使用循环,少用递归

                 只在一些使用循环解决比较麻烦的场景使用递归

    <script>
        /*
            递归:
                - 调用自身的函数称为递归函数
                - 递归的作用和循环基本一致

        */

        // 创建一个函数,可以用来求任意数的阶乘
        /*
            1! 1
            2! 1 x 2
            3!  1 x 2 x 3
            ...

            如果用递归来解决阶乘的问题
                5! = 4! * 5
                4! = 3! * 4
                3! = 2! * 3
                2! = 1! * 2
                1! = 1!

            递归的核心思想就是将一个大问题转化为一个个小问题

            编写递归函数,一定要包含两个条件:
                1.基线条件 —— 递归的终止条件
                2.递归条件 —— 如何对问题进行拆分

            递归的作用和循环是一致的,不同点在于,递归思路的比较清晰简介,循环的执行性能比较好
                在开发中,一般的问题都可以通过循环解决,也是尽量去使用循环,少用递归
                    只在一些使用循环解决比较麻烦的场景使用递归

        */
 
        // 采用循环思想
        function jieChen(num){

            // 创建一个变量用来记录结果
            let result = 1

            for(let i=2; i<=num; i++){
                result *= i
            }

            return result
        }


        // 采用递归思想
        function jieChen2(num){

            // 设置基线条件
            if(num === 1){
                return 1
            }

            // 设置递归条件
            // num! = (num-1) * num
            return jieChen2(num-1) * num

        }

        // 传入实参调用
        result = jieChen2(5)

        console.log(result)

        /*
            jieCheng2(5)
                - return jieCheng2(4) * 5
                 - return jieCheng2(3) * 4 
                  - return jieCheng2(2) * 3 
                   - return jieCheng2(1) * 2
                    - return 1

            “可以理解为((((1 * 2) * 3) * 4) * 5)”  

        */

    </script>

递归的练习

 <script>
        /*
            一堆兔子出生后的两个月每个月都能生一堆小兔子
                - 编写一个函数,可以计算第n个月兔子的数量

            月份 1  2  3  4  5  6  7  8  9  10  11  12
            数量 1  1  2  3  5  8  13 21  34... \
            - 规律,当前数等于前两个数之和(斐波那契数列) 
        */

        // 求斐波那契数列中第n个数
        function fib(n){

            // 确定基线条件
            if(n < 3){
                return 1
            }

            // 设置递归条件
            // 第n个数 = 第 n-1 个数 + 第 n-2 个数
            return fib(n - 1) + fib(n - 2)
        }

        result = fib(5)
    </script>

一一一、JavaScript——数组的方法

一、排序 

 sort():

  • sort用来对数组进行排序(会改变原数组)
  • sort默认会将数组升序排列,
  • 注意:sort默认会按照Unicode编码进行排序,所以如果直接通过sort对数字进行排序,可能会得到一个不正确的结果

  参数                 

  •  可以传递一个回调函数作为参数,通过回调函数来指定排序规则

                        - 参数为(a, b) => a - b ,升序排列

                        - 参数为(a, b) => b - a ,降序排列

 
        let arr = ["a", "c", "e", "f", "d", "b"]

        /*
            sort()
                - sort用来对数组进行排序(会改变原数组)
                - sort默认会将数组升序排列
                    注意:sort默认会按照Unicode编码进行排序,所以如果直接通过sort对数字进行排序
                        可能会得到一个不正确的结果
                - 参数:
                    - 可以传递一个回调函数作为参数,通过回调函数来指定排序规则
                        - 参数为(a, b) => a - b ,升序排列
                        - 参数为(a, b) => b - a ,降序排列



                    
        */

        // let arrs = arr.sort()

        // sort函数内传入参数
        arr.sort((a, b) => a - b) // 参数为(a, b) => a - b ,升序排列
        arr.sort((a, b) => b - a) // 参数为(a, b) => b - a ,降序排列

        console.log(arr)

 二、遍历

           forEach()

                - 用来遍历数组

                - 它需要一个回调函数作为参数,这个回调函数会被调用多次

                    - 数组中有几个元素,回调函数就会调用几次

                    - 每次调用,都会将数组中的数据作为参数传递

                - 有三个参数

                    element: 当前数组中的元素

                    index: 当前元素的索引

                    array: 被遍历的数组

 

        /*
            forEach()
                - 用来遍历数组
                - 它需要一个回调函数作为参数,这个回调函数会被调用多次
                    - 数组中有几个元素,回调函数就会调用几次
                    - 每次调用,都会将数组中的数据作为参数传递
                - 回调函数中有三个参数
                    element: 当前数组中的元素
                    index: 当前元素的索引
                    array: 被遍历的数组
        */

        arr = ["甲", "乙", "丙", "丁"]

        // 括号中传入一个匿名函数作为回调函数
        arr.forEach((element) => {

            console.log(element)

        })

        arr.forEach((element, index, array) => {

            console.log(index,element,array)

        })

三、过滤

 filter()

  •  用来过滤数组中的元素,将数组中中符合条件的元素保存到新数组中
  • 需要一个回调函数作为参数,会为每一个元素去调用回调函数,并根据返回值来决定是否将元素添加到数组中
  • 非破坏性方法,不会影响原数组
  • - 有三个参数

                        element: 当前数组中的元素

                        index: 当前元素的索引

                        array: 被遍历的数组


        /*
            filter()
                - 用来过滤数组中的元素,将数组中中符合条件的元素保存到新数组中
                - 需要一个回调函数作为参数,会为每一个元素去调用回调函数,并根据返回值来决定是否将元素添加到数组中
                - 非破坏性方法,不会影响原数组
        */

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

        // 获取数组中的偶数
        let result = arr.filter(ele => ele % 2 == 0)

        console.log(result)

 四、map重新生成新的数组

map()

                - 根据当前数组生成一个新数组

                - 有三个参数

                    element: 当前数组中的元素

                    index: 当前元素的索引

                    array: 被遍历的数组

 五、reduce整合数组

            reduce()

                - 可以将一个数组中的所有元素整合成一个值

                - 需要回调函数作为参数


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

        // reduce((第一个参数,第二个参数) => a + b, 初始值)
        result = arr.reduce((a, b) => a + b, 10)
        
        console.log(result)  // 输出结果46
        

一一二、JavaScript——可变参数

一、arguments获取实参

arguments:

                - arguments是函数中又一个隐藏参数

                - arguments是一个类数组对象(伪数组)

                    和数组相似,可以通过索引来读取元素,也可以通过for循环变量,但是它不是一个数组对象,不能调用数组的方法

                - arguments用来存储函数的实参

                    无论用户是否定义形参,实参都会存储到arguments对象中

                    可以通过该对象直接访问实参:arguments[元素下标] 访问数组中该元素下标的元素

               

                优点:函数不用定义形参,arguments可以直接获取实参,不受参数数量限制(arguments对于函数来说,定不定义形参都一样,并不影响arguments读取实参)

 function fn(){
            // arguments[1] 访问数组中元素下标为1的元素
            // console.log(arguments[1])
            
            // 利用isArray判断是否是数组,结果为false
            // console.log(Array.isArray(arguments))

            // 利用for循环进行遍历
            // for(let i = 0; i < arguments.length; i++){
            //     console.log(arguments[i])
            // }

            // 利用for-of遍历
            // for(let v of arguments()){
            //     console.log(v)
            // }



            // 定义一个函数,可以用来计算任意两个数值的和
            // 优点:函数不用定义形参,arguments可以直接获取实参,不受参数数量限制
            function sum() {
                let result = 0

                // 利用arguments获取数组中的元素
                for(let num of arguments){

                    result += num
                }
                return result
            }
        }

 二、可变参数

可变参数:在定义函数时可以将参数指定为可变参数

                语法 function 函数名(...参数名)

                - 可变参数可以接收任意数量实参,并将他们统一存储到一个数组中返回

                - 可变参数的作用与arguments基本一致,但是也具有一些不同点

                    1.可变参数的名字可以自己指定

                    2.可变参数就是数组,可以直接使用数组的方法

                    3.当可变参数与其他参数一起使用时,可变参数需要写到最后

                        - function 函数名(参数1, 参数2, ...ages)


        /*
            可变参数:在定义函数时可以将参数指定为可变参数
                语法: function 函数名(...参数名)

                - 可变参数可以接收任意数量实参,并将他们统一存储到一个数组中返回
                - 可变参数的作用与arguments基本一致,但是也具有一些不同点
                    1.可变参数的名字可以自己指定
                    2.可变参数就是数组,可以直接使用数组的方法
                    3.当可变参数与其他参数一起使用时,可变参数需要写到最后
                        - function 函数名(参数1, 参数2, ...ages)

        */

        // 括号中的参数是可变参数,可传入任意数量任意类型的参数
        function fn2(...ages){

            console.log(args)
        }
        

        // 传入实参
        fn2(1, "甲")

一一三、JavaScript——call和apply

调用函数除了通过 函数() 这种形式外,还可以通过其他方式来调用函数

                比如:我们可以通过调用函数的call()和apply()两个方法来调用函数

                    函数.call()

                    函数.apply()

                    - call 和 apply除了可以调用函数,还可以用来指定函数中的this

                    - call 和 apply的第一个参数,将会成为函数的this

                    - 通过 call 方法调用函数,函数的实参直接在第一个参数后一个一个的列出来

                    - 通过apply方法调用函数,函数的实参需要通过一个数组传递

                call和apply 不同点在于传实参方式

                    - call传实参直接传

                    - apply传实参需要通过数组的方式传

 <script>
        /*
            arguments
                - arguments是函数中又一个隐藏参数
                - arguments是一个类数组对象(伪数组)
                    和数组相似,可以通过索引来读取元素,也可以通过for循环变量,但是它不是一个数组对象,不能调用数组的方法
                - arguments用来存储函数的实参
                    无论用户是否定义形参,实参都会存储到arguments对象中
                    可以通过该对象直接访问实参:arguments[元素下标] 访问数组中该元素下标的元素
                
                优点:函数不用定义形参,arguments可以直接获取实参,不受参数数量限制
        */

        function fn(){
            // arguments[1] 访问数组中元素下标为1的元素
            // console.log(arguments[1])
            
            // 利用isArray判断是否是数组,结果为false
            // console.log(Array.isArray(arguments))

            // 利用for循环进行遍历
            // for(let i = 0; i < arguments.length; i++){
            //     console.log(arguments[i])
            // }

            // 利用for-of遍历
            // for(let v of arguments()){
            //     console.log(v)
            // }



            // 定义一个函数,可以用来计算任意两个数值的和
            // 优点:函数不用定义形参,arguments可以直接获取实参,不受参数数量限制
            function sum() {
                let result = 0

                // 利用arguments获取数组中的元素
                for(let num of arguments){

                    result += num
                }
                return result
            }
        }

        /*
            可变参数:在定义函数时可以将参数指定为可变参数
                语法: function 函数名(...参数名)

                - 可变参数可以接收任意数量实参,并将他们统一存储到一个数组中返回
                - 可变参数的作用与arguments基本一致,但是也具有一些不同点
                    1.可变参数的名字可以自己指定
                    2.可变参数就是数组,可以直接使用数组的方法
                    3.当可变参数与其他参数一起使用时,可变参数需要写到最后
                        - function 函数名(参数1, 参数2, ...ages)

        */

        // 括号中的参数是可变参数,可传入任意数量任意类型的参数
        function fn2(...ages){

            console.log(args)
        }
        

        // 传入实参
        fn2(1, "甲")
    
    </script>

 一一四、JavaScript——bind

bind() 是函数的方法,可以用来创建一个新的函数

                - bind可以为新函数绑定this

                - bind可以为新函数绑定参数

箭头函数没有自身的this,它的this由外层作用域决定

                - 也无法通过call apply 和 bind修改它们的this

                - 箭头函数中没有arguments


        function fn() {
            console.log("fn执行了---", this)
        }

        // 由于函数是bind绑定后生成的,新函数 newFn 的 this 就绑定为obj
        const newFn = fn.bind(obj)

        newFn()


        const arrowFn = () => {
            console.log(this)
        }

        // 箭头函数的this由函数外层作用域决定,arrowF外层是window,无法通过传参改变this的指向
        arrowFn.apply(obj)  // 打印window
        arrowFn.call(obj)   // 打印window

 一一五、JavaScript——数组的解构

    <script>
        /* 
            解构赋值
        */

        // 需求,将数组中的三个元素赋值给三个变量
        const arr = ["甲", "乙", "丙"]

        let a, b, c

        // 1. 传统方法:根据元素下标赋值
         a = arr[0]
         b = arr[1]
         c = arr[2]

        // 2.解构赋值方法
        [a, b, c] = arr;  // 解构赋值


        // 3.解构赋值的直接声明即使用,声明同时解构
        let [d, e, f] = arr


        // 4.解构数组时,可以使用...来设置获取多余的元素
        // ...n3即将剩下的元素全部塞到n3中,剩余两个,所以n3是个数组[6, 7]
        let [n1, n2, ...n3] = [4, 5, 6, 7];
        
        // 5.可以通过解构赋值来快速交换两个变量的值
        let a1 = 10 
        let a2 = 20

        [a1, a2] = [a2, a1];  // a1 和 a2 的值互相交换

        const arr = ["a", "b"]
        [arr[0], arr[1]] = [arr[1], arr[0]];

        console.log(a, b, c)

        /*
            数组中可以存储任意类型的数据,也可以村数组
                如果一个数组中的元素还是数组,则这个数组我们就称之为二位数组

        */

        // 二位数组的嵌套解构
        const arr3 = [["孙悟空", 18, "男"], ["猪八戒", 28, "男"]]

        let[[name, age, gender]] = arr3

        console.log(name, age, gender) 

    </script>

一一六、JavaScript——对象的解构

    <script>

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

        // 1.声明的同时解构
       // let { name, age, gender } = obj

        // 2. 先声明,再解构
        let name, age, gender 

        ({name, age, gender} = obj)

        // 这种解构写法是错误的,不能以大括号开头,应该跟上面的写法一样
        // {name, age, gender} = obj

        // 3.没有的属性,返回undefindeed
        let { address } = obj  

        // 4.通过冒号,来指定别名,将属性值赋值给了别名
        // 语法 let { 属性名:别名}
        let {name:a, age:b, gender:c} = obj

    </script>

 一一七、JavaScript——对象的序列化

            对象的序列化

                - JS中的对象使用时都是存在于计算机的内存中

                - 序列化指的将对象转化为一个可以存储的格式

                    在JS中对象的序列化通常是将一个对象转化为字符串(JSON字符串)

                - 序列化的用途(对象转化为字符串有什么用)

                    - 对象转化为字符串后,可以将字符串在不同的语言之间进行传递

                        甚至人可以直接对字符串进行读写操作,使得JS对象可以不同的语言之间传递

                - 如何进行序列化

                    - 在JS中有一个工具类 JSON (JavaScript Object Notation) JS对象表示法

                    - JS对象序列化后会换一个字符串,这个字符串我们就称为JSON字符串

                        - JSON.stringify(对象) 可以将一个对象转化为JSON字符串

                        - JSON.parse(字符串) 可以将一个JSON格式的字符串转化为JS对象

            用途:

                1. 作为数据交换的格式

                2. 用来编写配置文件

 // 1.创建对象obj
        const obj = {
            name: "孙悟空",
            age: 18
        }
        
        // 2.将obj对象转化为JSON对象
        const str = JSON.stringify(obj)  // JSON.stringify(对象) 可以将一个对象转化为JSON字符串

        const obj2 = JSON.parse(str)  // JSON.parse(字符串) 可以将一个JSON格式的字符串转化为JS对象

        console.log(obj)  // 打印{name: '孙悟空', age: 18}对象
        console.log(str)  // 打印字符串{"name": "孙悟空", age: 18},类型string


        // 手写的JSON对象
        const str2 = '{"name":"猪八戒","age":28}'

           - 也可以手动编写JSON字符串,在很多程序的配置文件就是使用JSON编写的

                - 编写JSON的注意事项

                    1. JSON字符串有两种类型

                        JSON对象 {}   const str = '{}'

                        JSON数组 []   const str = '[]'

                    2. JSON对象的属性名必须使用双引号引起来

                    3. JSON中可以使用的属性值(元素)

                            - 数字 (Number)

                            - 字符串 (String) 必须使用双引号

                            - 布尔值 (Boolean)

                            - 空值 (Null)

                            - 对象 (Object {})

                            - 数组 (Array [])

                    4. JSON的格式和JS对象的格式基本上一致的,

                        注意:JSON字符串如果属性是最后一个,则不要加逗号

      // JSON对象
        const str3 = '{}'
        // JSON数组
        const str4 = '[]'
        // 对象的属性名使用双引号
        const str5 = '{"name":"孙悟空", "age":18}'

 一一八、JavaScript——使用JSON进行深刻复制

 利用JSON来完成深复制

                1.先利用JSON.stringify(对象)将对象转化为JSON字符串

                2.再利用JSON.parse(JSON字符串)将字符串转化为对象,从而完成深复制

    <script>
         const obj = {
            name: "孙悟空",
            friend:{
                name:"猪八戒"
            }
        }

        // 对obj进行浅复制
        const obj2 = Object.assign({}, obj)

        // 对obj进行深复制
        const obj3 = structuredClone(obj)

        /*

            利用JSON来完成深复制
                1.先利用JSON.stringify(对象)将对象转化为JSON字符串
                2.再利用JSON.parse(JSON字符串)将字符串转化为对象,从而完成深复制

        */

        // 利用JSON来完成深复制,
        const str = JSON.stringify(obj)
        const obj4 = JSON.parse(str)

    </script>

 一一九、JavaScript——Map

 Map

  •  Map用来存储键值对结构的数据(Key-value)
  • Object中存储的数据就可以认为是一种键值对结构
  • Map和Object的主要区别
  • Object中的属性名只能是字符串或者符号,如果传递了一个其他类型的属性名

                            JS解释器会自动将其转化为字符串

  • Map中任何类型的值都可以称为数据的key

    const obj = {
            "name": "孙悟空",    // 字符串
            "age": 18,          // 字符串
            [Symbol()]: "哈哈"  // 符号
        }

 创建:

         new Map()

属性和方法:

  • map.size() 获取map中键值对的数量、
  • map.set(key, value) 向map中添加键值对
  • map.get(key) 根据key获取map中的值
  • map.delete(key) 删除指定的数据
  • map.has(key) 检查map中是否包含指定键
  • map.clear() 删除全部的键值对
 const obj2 = {}

        // 1.创建一个Map
        const map = new Map()

        // 2.通过set向map中添加键值
        map.set("name", "孙悟空")
        map.set(NaN, "哈哈哈")
        

一二零、JavaScript——Map补充

    <script>

        const map = new Map()

        map.set("name", "孙悟空")
        map.set("age", 18)

        // 将map转化为数组
        const arr = Array.from(map) // arr数组为 [["name","孙悟空"],["age", 18]]

        // 利用展开运算符将map转化为数组
        const arr1 = [...map]

        // 通过二位数组构建Map
        const map2 = new Map([["name", "猪八戒"], ["age", 18], [{}, () => {}]])

        // 通过for-of 遍历map
        for(const [key, value] of map) {

            console.log(key, value)
        }

        // 通过forEach 遍历map
        map.forEach((key, value)=>{
            console.log(key,value)
        })

        /*
            map.keys()   获取map的所有key
            map.values()  获取map的所有value
        */

        // 遍历key
        for(const key of map.keys()){
            console.log(key)
        }

        // 遍历value
        for(const value of map.values()){
            console.log(value)
        }

    </script>

一二一、JavaScript—Set

     Set

                - Set用来创建一个集合

                - 它的功能和数组类似,不同点在于Set中不能存储重复的数据

                - 利用Set中不能存储重复的数据实现去重功能

               

            - 使用方式

                创建

                    - new Set()

                    - new Set([...]) 根据数组创建一个集合

            方法

                size() 获取数据

                add() 添加元素

                has() 检查元素

                delete() 删除元素

<script>
        /*
            Set
                - Set用来创建一个集合
                - 它的功能和数组类似,不同点在于Set中不能存储重复的数据
                - 利用Set中不能存储重复的数据实现去重功能
                
            - 使用方式
                创建
                    - new Set()
                    - new Set([...]) 根据数组创建一个集合

            方法
                size() 获取数据
                add() 添加元素
                has() 检查元素
                delete() 删除元素


        */

        // 创建一个Set
        const set = new Set()

        // 向Set中添加数据
        set.add(10)
        set.add("甲")
        // set.add(10)   Set的add方法不能添加重复的数据


        // 使用for循环遍历set中的内容
        for(const value of set){

            console.log(value)
        }

        // 取set中的单个元素,利用展开运算符将set转化为数组,再从数组中取值‘
        const arr = [...set]
        console.log(arr[0])  // 取数组中下标为0的元素


        // 数组中有重复的数组,利用set不能有重复的元素来去重
        const arr2 = [1,2,2,3,4,4,5,5,6,1,1,2,3,3]

        const set2 = new Set(arr2)

        console.log(set2)  // 打印出来为一个集合 {1,2,3,4,5,6}

        // 如果需要打印出来为一个数组,添加中括号即可
        const set3 = new Set(arr2)

        // 添加中括号,再添加展开运算符,即为数组
        console.log([...set3])  // 打印出来为一个数组 [1,2,3,4,5,6]
    </script>

 一二二、JavaScript—Math

 Math

                - Math是一个工具类

                - 但是Math不能New,它是一个方法,适用于直接调用方法“Math.方法"

                - Math中为我们提供了数字运算相关的常量和方法

                - MDN文档中的Math的介绍: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math

               

                - 常量

                    Math.PI 圆周率

                - 方法

                    Math.abs() 求一个数的绝对值

                    Math.min() 求多个信中的最小值

                    Math.max() 求多个值中的最大值

                    Math.min() 求多个值中的最小值

                    Math.pow(x,y) 求x的y次幂

                    Math.sqrt() 求一个数的平方根

                - 取整的四个方法

                    Math.floor() 向下取整

                    Math.ceil() 向上取整

                    Math.round() 四舍五入取

                    Math.trunc() 去除小数位

                - 随机生成一个0到1之间的随机数

                    Math.random()

                - 随机生成一个0到x之间的随机数,包括0也包括x

                    Math.round(Math.random() * x)


        // 圆周率
        console.log(Math.PI)

        // 求绝对值
        let result = Math.abs(-19)

        // 求x的y次幂
        result = Math.pow(2, 4)

        // 向下取整 结果为1
        result = Math.floor(1.22)  

        // 向上取整 结果为3
        result = Math.ceil(2.22)

        // 四舍五入取 结果为3
        result = Math.round(3.333)

        // 去除小数位 结果为4
        result = Math.trunc(4.12234)


        // 利用for循环生成0到1之间的随机数,i代表生成的数量
        for(let i= 0;i< 5;i++) {

            // 生成0到5之间的随机数,包括0也包括5.利用round取整
            result = Math.round(Math.random * 5)
        }

 一二三、JavaScript—Date日期

 Date日期

                - 日期对象的创建

                    - 在JS中所有的和时间相关的数据都由Date对象来表示

                    - 直接通过new Date创建对象时,它创建的是当前的时间对象

                    - 可以在Date()的构造函数中,传递一个表示时间的字符串

                    - 字符串的格式:月/日/年 时:分:秒

                    - 字符串的格式:年-月-日T时:分:秒

                - 日期对象的方法

                    - getFullYear() 获取四位年份 例:2022

                    - getMonth() 返回当前日期的月份(0-11)

                    - getDate() 获取当前几日

                    - getDay() 返回当前是周几(0-6) 0代表周日

                    - getTime() 获取当前日期对象的时间戳

                        时间戳:自1970年1月1日0点0分0秒到当前时间所经历的毫秒数

                        计算机底层存储时间时,使用的都是时间戳

                    - Date.now()获取当前的时间戳

    <script>
        /*
            Date日期
                - 日期对象的创建
                    - 在JS中所有的和时间相关的数据都由Date对象来表示
                    - 直接通过new Date创建对象时,它创建的是当前的时间对象
                    - 可以在Date()的构造函数中,传递一个表示时间的字符串
                    - 字符串的格式:月/日/年 时:分:秒
                    - 字符串的格式:年-月日T时:分:秒
                - 日期对象的方法
                    - getFullYear() 获取四位年份 例:2022
                    - getMonth() 返回当前日期的月份(0-11)
                    - getDate() 获取当前几日
                    - getDay() 返回当前是周几(0-6) 0代表周日 
                    - getTime() 获取当前日期对象的时间戳
                        时间戳:自1970年1月1日0点0分0秒到当前时间所经历的毫秒数
                        计算机底层存储时间时,使用的都是时间戳
                    - Date.now()获取当前的时间戳
         
        */
       let d = new Date()

        //  创建指定时间
        // 可以在Date()的构造函数中,传递一个表示时间的字符串
        // 字符串的格式:月/日/年 时:分:秒
        // 字符串的格式:年-月日T时:分:秒
        d = new Date("12/20/1998 12:12:33")

        // getFullYear() 获取四位年份
        result = d.getFullYear() // 获取四位年份 2019

        // getMonth()获取当前月份,
        result = d.getMonth()

        // getDate()获取当前日期
        result = d.getDate()

        // getDay()获取当前周几(0-6)
        result = d.getDay()

        // getTime()获取当前日期对象的时间戳
        result = d.getTime()

    </script>

 一二五、JavaScript—包装类

            在JS中,除了直接创建原始值外,也可以创建原始值的对象

                通过 new String() 可以创建String类型的对象

                通过 new Number() 可以创建Number类型的对象

                通过 new Boolean() 可以创建Boolean类型的对象

                    - 但是千万不要这么做

            包装类:

                JS中一共有五个包装类

                    String -- > 字段包装为String对象

                    Number -- > 字段包装为Number对象

                    Boolean -- > 布尔值包装为布尔类型对象

                    BigInt -- > 大整数包装为BigInt对象

                    Symbol -- > 符号包装为Symbol对象

                     - 通过包装类可以将一个原始值包装为一个对象

                        当我们对一个原始值调用方法成属性时,JS解释器会临时将原始值包装为对应的对象

                            然后调用这个对象的属性或方法

                - 由于原始值会被临时转换为对应的对象,这就意味着对象中的方法都可以通过自身原始值来调用

<script>
        /*
            在JS中,除了直接创建原始值外,也可以创建原始值的对象
                通过 new String() 可以创建String类型的对象
                通过 new Number() 可以创建Number类型的对象
                通过 new Boolean() 可以创建Boolean类型的对象
                    - 但是千万不要这么做

            包装类:
                JS中一共有五个包装类
                    String -- > 字段包装为String对象
                    Number -- > 字段包装为Number对象
                    Boolean -- > 布尔值包装为布尔类型对象
                    BigInt -- > 大整数包装为BigInt对象
                    Symbol -- > 符号包装为Symbol对象
                     - 通过包装类可以将一个原始值包装为一个对象
                        当我们对一个原始值调用方法成属性时,JS解释器会临时将原始值包装为对应的对象
                            然后调用这个对象的属性或方法

                - 由于原始值会被临时转换为对应的对象,这就意味着对象中的方法都可以通过自身原始值来调用
        */
       
        // 通过原始值创建对象
        let str = "hello"
        let num = 10
        let boot = true

        // 通过 new 一个类创建对象,但是千万不要这么做
        let str1 = new String("hello")
        let num1 = new Number(11)
        let boot1 = new Boolean(true)


        let str2 = "hello"
        str2.name = "哈哈"

        
    </script>

 一二六、JavaScript—字符串的方法

 MDN前端参考文档:           

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String

            字符串:

                - 字符串其本质就是一个字符数组

                    - let str = "hello" 的存储方式

                    - "hello" -- > ["h", "e", "l", "l", "o"]

                    - 字符串的很多方法搜和数组非常类似

                    - 属性和方法

                        字符串.length:

                            获取字符串的长度

                        字符串[索引]:

                             获取指定位置的字符

                        字符串.at(索引):

                             根据索引获取字符,可以接受负索引

                        字符串.charAt(索引)

                             根据索引获取字符

                        字符串.concat()

                             用来连接两个或多个字符串

                        str.includes()

                             用来检查字符串中是否包含某个内容

                                有则返回true

                                没有则返回false

                        str.indexOf()

                        str.lastIndexOf()

                              查询字符串中是否包含某个内容

                              st有就返回该字符串的索引

                        str.startWith()

                              检查一个字符串是否以指定内容开头

                        str.endWith()

                              检查一个字符串是否以指定内容结尾

                        str.padStart()

                        str.padEnd()

                               通过添加指定的内容,使字符串保存某个长度

                        str.replace()

                                使用一个新字符串替换一个指定内容

                        str.replaceAll()

                                使用一个新字符串替换所有指定内容

                        str.subString()

                                截取字符串

                        str.spilt()

                                用来将一个字符串转化为数组

                        str.toLowerCase()

                                将字符串转化为小写

                        str.toUpperCase()

                                将字符串转化为大写

                        str.trim()

                                去除字符串的前后空格

                        str.trimStart()

                                去除字符串前面的空格

                        str.trimEnd()

                                去除字符串后面的空格

一二七、JavaScript—正则表达式简介

正则表达式(规则表达式)

                - 正则表达式用来定义一个规则

                - 通过这个规则计算机可以检查一个字符串是否符合规则

                    或者字符串中符合规则的内容提取出来

                -  正则表达式也是JS中的一个对象

                    所以要使用正则表达式,需要先创建正则表达式的对象

    <script>
        /*
            正则表达式(规则表达式)
                - 正则表达式用来定义一个规则
                - 通过这个规则计算机可以检查一个字符串是否符合规则
                    或者字符串中符合规则的内容提取出来 
                -  正则表达式也是JS中的一个对象
                    所以要使用正则表达式,需要先创建正则表达式的对象
        */

        // 通过构造函数来创建一个正则表达式的对象
        // new RegExp(正则表达式,匹配模式) 
        let reg = new RegExp("a", "i")

        console.log(reg)  // 打印内容 /a/i

         // 使用字面量来创建正则表达式: /正则表达式/匹配模式
         reg = /a/i

         /*
            通过正则表达式检查一个字符串是否符合规则
         */

         reg = new RegExp("a")  // /a/ 检查字符串中是否有a,只要含有a,就true

         // 检查是否符合规则
         let result = reg.test(str)

         console.log(result)      // 打印结果true
         result = reg.test("b")   // 打印结果false
         result = reg.test("abc") // 打印结果true
    </script>

 一二八、JavaScript—正则表达式中的字符

MDN前端参考文档正则表达式:

http:// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp

            https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions

正则表达式创建

  1. new RegExp(正则表达式,匹配模式)
  2.   /正则表达式/匹配模式

            1. 在正则表达式中大部分字符串都可以直接写

            2. | 在正则表达式中表示或: re1 = /a|b/ 检查字符串是否包含a或者b

            3. [字符集] 表示字符集:re1 = [ab] 检查字符串是否包含a或者b

                [a--z] 任意的小写字母

                [A--Z] 任意的大写字母

                [a--zA--Z] 任意的字母

                [a--z]/i 忽略大小写 i即ignore

                [0--9] 任意数字

            4.[^] 表示除了

                [^x] 除了x

            5. /./表示除了换行以外的任意字符

            6. 在正则表达式中使用\作为转义字符

            7.其他的字符集

                \w 匹配基本拉丁字母中的任何字母数字字符,包括下划线 相当于 [A-Za-z0-9_]

                \W  匹配任何不是来自基本拉丁字母的单词字符。相当于 [^A-Za-z0-9_]

                \d  匹配任何数字 (阿拉伯数字)。相当于 [0-9]

                \D  匹配任何非数字 (阿拉伯数字) 的字符。相当于[^0-9]

                \s  匹配单个空白字符,包括空格、制表符、换页符、换行符和其他 Unicode 空格。相当于 [\f\n\r\t\v\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]

                \S  匹配除空格以外的单个字符。相当于 [^\f\n\r\t\v\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]

                8. 开头和结尾

                    ^ 表示字符串的开头

                    $ 表示字符串的结尾


    <script>
        /*
            MDN前端参考文档正则表达式:
            https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp
            https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
            正则表达式创建
                1. new RegExp(正则表达式,匹配模式)
                2. /正则表达式/匹配模式
            
            1. 在正则表达式中大部分字符串都可以直接写
            2. | 在正则表达式中表示或: re1 = /a|b/ 检查字符串是否包含a或者b 
            3. [字符集] 表示字符集:re1 = [ab] 检查字符串是否包含a或者b
                [a--z] 任意的小写字母
                [A--Z] 任意的大写字母
                [a--zA--Z] 任意的字母
                [a--z]/i 忽略大小写 i即ignore
                [0--9] 任意数字
            4.[^] 表示除了
                [^x] 除了x
            5. /./表示除了换行以外的任意字符
            6. 在正则表达式中使用\作为转义字符
            7.其他的字符集
                \w 匹配基本拉丁字母中的任何字母数字字符,包括下划线 相当于 [A-Za-z0-9_]
                \W  匹配任何不是来自基本拉丁字母的单词字符。相当于 [^A-Za-z0-9_]
                \d  匹配任何数字 (阿拉伯数字)。相当于 [0-9]
                \D  匹配任何非数字 (阿拉伯数字) 的字符。相当于[^0-9]
                \s  匹配单个空白字符,包括空格、制表符、换页符、换行符和其他 Unicode 空格。相当于 [\f\n\r\t\v\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]
                \S  匹配除空格以外的单个字符。相当于 [^\f\n\r\t\v\u0020\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]
                8. 开头和结尾
                    ^ 表示字符串的开头
                    $ 表示字符串的结尾
        */
       let re = /ab/

       let re1 = /a|b/  // 检查整体是否存在a或者b
       
       let result = re.test('abc')

       let result1 = re.test('acb')  // false 上面的规则是a在b的左边,b在a的右边

       console.log(result) // 打印结果为true

       let res = /abc|bcd/ // 字符串是否包含abc或bcd
       re = /[a--z]/      //字符串是否包含小写的a到z
       re = /[A--Z]/      //字符串是否包含大写的A到Z
       re = /[a--zA--Z]/  //字符串是否包含所有的字母
       re = /[a--z]/i     //字符串是否包含所有的字母(有i代表忽视小写)
       re = /[a--zA--Z]/  //字符串是否包含所有的字母
       re = /[^a-z]/      //字符串是否包含除了小写a到z的其他元素
       re = /./           //字符串是否包含除了换行以外的任意字符
       re = /\./           //利用转义字符加.的方式,表示字符串是否包含点
       re = /\w/           //表示字符串是否包含任意的单词字符

       re = /^a/            // 匹配开始位置的a

       re = /a$/            // 匹配结束位置的a

       re = /^a$/           // 匹配开头和结尾都是a,但是要求完全匹配 aa 就不行, 因为这个要求a开头马上就以这个a结尾



    </script>

一二九、JavaScript—正则表达式 

 <script>
        /*
            /a{3}/: 连续3个a
            /(ab){3}/: 连续3个ab
            /[a-z]{3}/: 连续3个a到z的字母
            量词
                
                /变量{m}/ : 变量出现m个
                /变量{m,}/ : 变量至少出现m个
                /变量{m,n}/ : 变量至少出现m到n个
                /变量+ / : 一个以上,相当于{1,}
                /变量* / : 任意数量的变量
                /变量? / : 0到1次,可以没有,有的话最多一次
        */

        // 测试是否包含3个a
        let re = /a{3}/
        console.log(re.test("aaa"))  // true


        // 测试起始是3个a结尾也是3个a
        re = /^a{3}$/
        console.log(re.test("aaaa"))

        // 量词只对前一个变量起作用
        re = /^ab{3}$/     //相当于开头一个1结尾3个b

        // 两次想要对整体起作用需要加括号
        re = /^(ab){3}$/   //相当于开头3个ab结尾3个ab
        

    </script>

一三零、JavaScript—exec方法

  <script>
        /*

        re.exec()
            - 获取字符串中符合正则表达式的内容
        */
       let str = "abcaecafcacc"

       // 提取出str中符合axc格式的内容
       // i代表忽视小写,g代表全局匹配,如果没有g,只匹配符合条件的第一个
       let re = /a[a-z]c/ig

       let result = re.exec(str)

       // 中间加了括号 取到b e f 这些中间的值
       let res = /a([a-z])c/ig   // 取出的结果为abc b

       let r = res.exec(str)

       // 再加一层括号  
       let resu = /a(([a-z])c)/ig  // 取出的结果为abc b bc

       let rs = re.exec(str)

       // 利用while循环取出全部的值
       while(rs){
        /*
            打印结果:
            abc bc b
            aec ec e
            afc fc f
            acc cc c
        */
        console.log(rs[0],rs[1],rs[2])  
        rs = resu.exec(str)
       }
    </script>

 一三一、JavaScript——练习

    <script>
        /*
            将手机号从:acwedfrvefq13679541806adsdcsv18095498748gbrtvbdf16098763098 中取出

            先用自己得语言把规则描述出来
                例如: 号码13501789087
                第一位    1
                第二位    3到9之间
                剩余位置  任意数字  
        */

        //  \d{9}表示任意数字共有9个 /g表示全局匹配,都打印出来
         // let re = /1[3-9]\d{9}/g

        // 通过加括号和\d 来截取不同长度
        let re = /(1[3-9]\d)\d{4}(\d{4}})/g

        let str = "acwedfrvefq13679541806adsdcsv18095498748gbrtvbdf16098763098"

        let result 

        while ((result = re.exec(str))) {


            /*执行语句:let re = /1[3-9]\d{9}/g
             打印内容为:
            13679541806
            18095498748
            16098763098
            */ 
            //console.log(result[0])

             /*执行语句:let re = /(1[3-9]\d)\d{4}(\d{4}})/g
             打印内容为:
            13679541806 136 1860
            18095498748 180 8748
            16098763098 160 3098
            */ 
            console.log(result[0], result[1], result[2],)

              /*隐藏手机号
             打印内容为:
            136****1860
            180****8748
            160****3098
            */ 
            console.log(result[1]+"****"+result[2],)
            
        }
    </script>

一三二、JavaScript——字符串的正则方法

            split()

                - 可以根据正则表达式对一个字符串进行拆分

            search()

                - 可以去搜索符合正则表达式的内容第一次在字符串中出现的位置

            replace()

                - 根据正则表达式替换字符串中的指定内容

                - replace(被替换的内容,替换的具体内容)

            match()

                - 根据正则表达式去匹配字符串中符合要求的内容

            matchAll()

                - 根据正则表达式去匹配字符串中符合要求的内容(必须设置g 全局匹配)

                - 它返回的是一个迭代器

                - 返回迭代器后再用for-of遍历迭代器

     let str = "a@b@c@d"

       //1. 根据@符号对字符串进行拆分
       let result = str.split("@")

       //1. 打印结果为一个数组:[a b c d]
       console.log(result)

       str = "孙悟空abc猪八戒adc沙和尚"

       //2. 利用正则,中间是b或者d
       result = str.split(/a[bd]c/)

       //2. 打印结果为数组:['孙悟空','猪八戒','沙和尚']
       console.log(result)

       result = str.search("abc")

       //3. 返回3  如果搜索abcd 这种不存在的字符串 则返回-1
       console.log(result)

       str = "acwedfrvefq13679541806adsdcsv18095498748gbrtvbdf16098763098"

       //4. 搜索开头是1后面是3到9且连续9位的数据的位置, /d{9}指的是匹配任何数字连续9个
       result = str.search(/1[3-9]\d{9}/)

       // 打印结果为11
       console.log(result)


       //5. 将所有的数字替换成"哈哈哈",/g是替换所有,即全局匹配
       result = str.replace(/1[3-9]\d{9}/g, "哈哈哈")

       // 打印内容为:acwedfrvefq哈哈哈adsdcsv哈哈哈gbrtvbdf哈哈哈
       console.log(result)


       //6. 去字符串中找所有符合开头是1后面是3到9且连续9位的数据,
       result = str.match(/1[3-9]\d{9}/g)
       // 返回结果为数组["13679541806","18095498748","16098763098]
       console.log(result)

       //7. 去字符串中找所有符合开头是1后面是3到9且连续9位的数据(括号中必须加g即全局匹配) 
       result = str.matchAll(/1[3-9]\d{9}/g)

       // 返回的结果是迭代器,再用for-of遍历这个迭代器
       for(let item of result){
        /*
        打印结果为:[数据, 索引, 输入]
            ["13679541806", 11, "acwedfrvefq13679541806adsdcsv18095498748gbrtvbdf16098763098"]
            ["18095498748", 29, "acwedfrvefq13679541806adsdcsv18095498748gbrtvbdf16098763098"]
            ["16098763098", 48, "acwedfrvefq13679541806adsdcsv18095498748gbrtvbdf16098763098"]
        */
        console.log(item)
       }

 一三三、JavaScript——垃圾回收

程序中的垃圾定义:例一开始定义了一个对象,属性名为”孙悟空“,之后再令这个对象等于null,即不指向这个name属性了,这时候这个name属性没有被指向,就属于程序中的垃圾

 MDN前端参考文档位置:https://developer.mozilla.org/zh-CN/docs/Glossary/Garbage_collection

垃圾回收(Garbage_collection)

- 和生活一样,生活时间长了以后会产生生活垃圾

   程序运行一段时间后也会产生垃圾

 - 在程序中,什么是垃圾

 - 如果一个对象没有任何的变量对其进行引用,那么这个对象就是一个垃圾

 - 垃圾对象的存在,会严重影响程序的性能

 - 在JS中有自动的回收机制,这些垃圾对象会被解释器自动回收,我们无需手动处理

  - 对于垃圾回收来说,我们唯一能做的事情就是将不再使用的变量设置为null

    <script>
        /*
            
            MDN前端参考文档位置:https://developer.mozilla.org/zh-CN/docs/Glossary/Garbage_collection
                垃圾回收(Garbage_collection)
                    - 和生活一样,生活时间长了以后会产生生活垃圾
                        程序运行一段时间后也会产生垃圾
                    - 在程序中,什么是垃圾
                        - 如果一个对象没有任何的变量对其进行引用,那么这个对象就是一个垃圾
                        - 垃圾对象的存在,会严重影响程序的性能
                        - 在JS中有自动的回收机制,这些垃圾对象会被解释器自动回收,我们无需手动处理
                            - 对于垃圾回收来说,我们唯一能做的事情就是将不再使用的变量设置为null
            */

            let obj = { 
                name : "孙悟空"
            }

            // obj指向的对象是空,此时obj是垃圾对象
            obj = null 
    </script>

猜你喜欢

转载自blog.csdn.net/z972065491/article/details/128529122