js高级~复习(3)

函数的三种调用方式(this指向)

  1. 环境对象(this):谁调用我,我就指向谁

  2. 指向:

    • 普通函数----->window (函数名() 指向window)

    • 构造函数----->new 创建实例对象 (new 函数名) this指向new创建的实例对象)

    • 对象方法----->obj对象 (对象名.方法名( ) this指向对象)

      技巧:没点没new就是window,有new是实例,有点是点左边的对象

  3. 上下文调用:修改函数内部的this

    1. 函数名.call()
    2. 函数名.apply()
    3. 函数名.bind()
    4. 函数名.slice() 查询数组,默认情况下不传参这个方法会得到数组本身
    5. Array.from(伪数组) 实际开发中,ES6新增语法用于伪数组转真数组:

函数名.call(修改后的this,形参1,新参2…)

  1. call场景:数据类型检测

  2. typeof 数据 : 检测数据类型

    typeof有两种数据类型无法检测: null,array 都会得到object

  3. 检测数据类型固定格式语法: Object.prototype.toString.call(数据)

函数名.apply(修改后的this,数组或伪数组)

  1. 伪数组 本质是 : 对象

  2. 借助 apply自动遍历数组/伪数组 逐一传参特点

  3. 示范:

    //伪数组 
    	let obj = {
                0: 20,
                1: 50,
                2: 88,
                3: 66,
                length: 4
            }
            console.log(obj)
    //声明空数组
    	let newArr = []
    	newArr.push.apply(newArr,obj)
    	console.log(newArr)
    
  4. 比较最大值:

    //求数组最大值
            let arr = [10, 20, 50, 60, 88, 30]
    
            //1.排序法 : 从大到小排序,取0下标
            // arr.sort(function(a,b){
            //     return b-a
            // })
            // console.log(arr[0])//数组从大到小排序,第一个元素就是最大值
    
            //2.擂台法
            // let max1 = arr[0]
            // for(let i = 1;i<arr.length;i++){
            //     if( arr[i]>max1){
            //         max1 = arr[i]
            //     }
            // }
            // console.log( max1 )
    
    
            //3.ES5 :  Math.max.apply(Math,数组名)
            //函数名.apply(修改的this, 数组/伪数组 )
            //第一个参数 Math : this本来就是Math,这里也不需要修改this (传Math相当于this不变)
            //第二个参数 arr : 借助apply特点。 自动遍历数组/伪数组。 逐一传参
            console.log(Math.max(10, 20, 50, 60, 88, 30))
            console.log(Math.max.apply(Math, arr))
    
            //4.ES6(推荐) :  ...和apply类似,也会自动遍历数组,然后逐一传参
            console.log(Math.max(...arr))
    

函数名.bind(修改后的this)

  1. bind不会立即执行函数,而是得到一个修改this之后的新函数(一次修改,终生受用)
  2. 细节: 如果你在bind后面传了函数参数,那么参数也会绑定。之后传参无效
  3. band一般用于修改:定时器函数、事件处理函数

call、apply、bind有什么区别

相同

  1. 修改函数的this指向

不同点

  1. 传参方式不同 : call是一 一传参,apply是数组/伪数组传参
  2. 执行机制不同 : call、apply会立即执行函数, bind不会立即执行函数

闭包

闭包(closure):

  • 闭包是一个访问其他函数内部变量的函数
  • 闭包 = 函数 + 上下文引用

闭包作用:

  • 解决变量污染

用处

  • 一般用于回调函数
button.onclick = function () {
            let num = 100
            function fn() {
                alert(num)
            }
            fn()
        }

递归

递归

  • 一个函数在内部调用自己

作用

  • 递归作用和循环类似,也需要有结束条件

递归应用

  • 深拷贝(利用JSON拷贝,拷贝的是数据,不是地址)

            //声明一个对象
            //拷贝: 把对象中存储的数据 拷贝一份赋值给其他对象
            let obj = {
                name: '张三',
                age: 18,
                sex: '男'
            }
            //浅拷贝: 拷贝的是地址  地址内的数据改动,数据全部改动
            let objs = obj
            objs.age = '30'
            console.log(objs) //{name: '李四', age: '30', sex: '男'}
            console.log(obj) //{name: '李四', age: '30', sex: '男'}
            //深拷贝: 拷贝的是数据 数据修改,只改单个数据不影响其他
            let ob = JSON.parse(JSON.stringify(obj))
            ob.name = '李四'
            console.log(ob) //{name: '李四', age: '30', sex: '男'}
            console.log(obj) //{name: '张三', age: '30', sex: '男'} /*     
    
    let obj = {
                name:'张三',
                age:18,
                hobby:['看书','唱歌','学习'],
                friend:{
                    name:'朋友',
                    sex:'男'
                }
            }  
            
            /* 
            (1)遍历obj,把所有的属性添加给newObj
            (2)如果obj[key]是引用类型(数组、对象),则不能直接拷贝地址
                (2.1)数组:给newObj声明一个空数组,然后遍历obj[key],把里面元素添加给newObj[key]
                (2.2)对象:给newObj声明一个空对象,然后遍历obj[key],把里面元素添加给newObj[key]
            (3)如果obj[key]不是引用类型,则直接赋值。结束递归
            */
    
            function kaobei(newObj,obj){
                for(let key in obj){
                    //判断 obj[key] 是不是数组类型
                    if( obj[key] instanceof Array ){
                        //声明一个空数组,然后继续拷贝数组里面的数据
                        newObj[key] = []
                        kaobei(newObj[key],obj[key])
                    }else if(obj[key] instanceof Object){
                        //声明一个空对象,然后继续拷贝数组里面的数据
                        newObj[key] = {}
                        kaobei(newObj[key],obj[key])
                    }else{
                        newObj[key] = obj[key]
                    }
                }
            }
    
            //调用深拷贝函数
            let newObj = {}
            kaobei(newObj,obj)
            //深拷贝:修改拷贝的数据,对原数据没有影响
            newObj.hobby[0] = '111'
            console.log( newObj,obj)
    
  • 遍历dom树

//服务器返回一个不确定的数据结构,涉及到多重数组嵌套
      let arr = [
        {
          type: '电子产品',
          data: [
            {
              type: '手机',
              data: ['iPhone手机', '小米手机', '华为手机']
            },
            {
              type: '平板',
              data: ['iPad', '平板小米', '平板华为']
            },
            {
              type: '智能手表',
              data: []
            }
          ]
        },
        {
          type: '生活家居',
          data: [
            {
              type: '沙发',
              data: ['真皮沙发', '布沙发']
            },
            {
              type: '椅子',
              data: ['餐椅', '电脑椅', '办公椅', '休闲椅']
            },
            {
              type: '桌子',
              data: ['办公桌']
            }
          ]
        },
        {
          type: '零食',
          data: [
            {
              type: '水果',
              data: []
            },
            {
              type: '咖啡',
              data: ['雀巢咖啡']
            }
          ]
        }
      ]
      
      //arr:数据   father:父盒子
      function addElement(arr,father){
        //遍历数组,生成div>p添加到父元素中
        for(let i = 0;i<arr.length;i++){
            //(1)创建空标签
            let div = document.createElement('div')
            //(2)设置内容
            div.innerHTML = `<p>${arr[i].type || arr[i]}</p>`
            //(3)添加到父盒子
            father.appendChild(div)
            //如果菜单还有data,说明还有子菜单,则需要继续遍历添加
            if( arr[i].data ){
                addElement(arr[i].data,div)
            }
        }
      }

      let menu = document.querySelector('.menu')
      //调用函数
      addElement(arr,menu)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值