JavaScript-异常与this处理与性能优化

1. 深浅拷贝

在这里插入图片描述

    const obj = {
      uname: 'nidie',
      age: 18
    }
    // o对象直接复制obj,直接赋值将obj的地址也给了o
    const o = obj
    // 正常打印18
    console.log(o);
    // 对o改动,打印obj,obj也被改动了
    o.age = 20
    console.log(o);
    console.log(obj);

1.1 浅拷贝

在这里插入图片描述
拷贝对象:Object.assgin()
拷贝数组:Array.prototype.concat()

    const obj = {
      uname: 'nidie',
      age: 18
    }

    // 浅拷贝
    const o = { ...obj }
    console.log(o);
    // 对未改动的obj没有影响
    o.age = 20
    console.log(o)
    console.log(obj);

    console.log('----------------------');

    // 利用assign方法浅拷贝
    const oo = {}
    Object.assign(oo, obj)
    oo.age = 20
    console.log(oo);
    console.log(obj);

    console.log('----------------------');

    // 但是浅拷贝仍然存在问题
    const objj = {
      uname: 'nidie',
      age: 18,
      family: {
        baby: 'son'
      }
    }
    const ooo = {}
    Object.assign(ooo, objj)
    // 简单数据类型age直接赋值没关系,obj对象中存储的family地址会给ooo
    ooo.age = 20
    ooo.family.baby = '牛魔'
    // 只想改变ooo的family对象里面的属性,却把objj的也改了
    console.log(ooo);
    console.log(objj);

总结:

在这里插入图片描述

1.2 深拷贝

在这里插入图片描述

递归实现深拷贝

在这里插入图片描述

    function getTime() {
      document.querySelector('div').innerHTML = new Date().toLocaleString()
      // 每隔一秒调用一次自己
      setTimeout(getTime, 1000)
    }
    getTime()

注意:

  1. 利用函数递归
  2. 普通属性直接赋值,遇到复杂数据类型,数组,对象则调用自己
  3. 数组的逻辑顺序要在对象前面
    const obj = {
      uname: 'nidie',
      age: 18,
      hobby: ['lu', 'lulu'],
      family: {
        baby: 'babybaby'
      }
    }
    const o = {}

    // 将obj拷贝给o
    function deepCopy(newObj, oldObj) {
      // 遍历旧对象
      for (let k in oldObj) {
        // if的逻辑顺序不能反,因为数组也属于对象,必须先筛选完数组再写对象
        // 处理数组的问题
        if (oldObj[k] instanceof Array) {
          // 再次遍历数组
          newObj[k] = []
          deepCopy(newObj[k], oldObj[k])
        }
        // 处理对象问题
        else if (oldObj[k] instanceof Object) {
          // 再次遍历
          newObj[k] = {}
          deepCopy(newObj[k], oldObj[k])
        }
        else {
          // k  属性名  oldObj[k] 属性值
          // newObj[k] === o.uname
          newObj[k] = oldObj[k]
        }
      }
    }
    deepCopy(o, obj) //o新对象 obj旧对象

    o.age = 20
    o.hobby[0] = 'bulu'
    o.family.baby = '牛魔'
    console.log(o);
    console.log(obj);

利用库函数直接深拷贝

  <script src="lodash.js"></script>
  <script>
    const obj = {
      uname: 'nidie',
      age: 18,
      hobby: ['lu', 'lulu'],
      family: {
        baby: 'babybaby'
      }
    }
    const o = _.cloneDeep(obj)
    console.log(o);

利用JSON实现深拷贝

    const obj = {
      uname: 'nidie',
      age: 18,
      hobby: ['lu', 'lulu'],
      family: {
        baby: 'babybaby'
      }
    }
    // 把对象转换为JSON字符串
    console.log(JSON.stringify(obj));

    // parse方法再将字符串转换为对象
    const o = JSON.parse(JSON.stringify(obj))
    console.log(o);
    
    o.family.baby = '牛魔'
    console.log(o)
    console.log(obj);;

总结

在这里插入图片描述

2. 异常处理

2.1 throw抛异常

在这里插入图片描述

    function fn(x, y) {
      if (!x || !y) {
        // throw '你没传参'
        // 抛出异常并终止程序
        throw new Error('没传参')
      }

      return x + y
    }
    console.log(fn());

总结

在这里插入图片描述

2.2 try/catch捕获异常

在这里插入图片描述

<body>
  <p>123</p>
  <script>
    function fn() {
      try {
        const p = document.querySelector('.p')
        p.style.color = 'red'
      }
      catch (err) {
        console.log(err.message);

        // 配合throw使用
        throw new Error('错了吧人才')
        return
      }
      finally {
        // 不管程序是否正确,一定会执行finnaly
        alert('你好')
      }
      // catch会拦截错误,但是不会中断程序执行  加入return中断程序
    }
    fn()
  </script>
</body>

总结

在这里插入图片描述

2.3 debugger

在这里插入图片描述

3. 处理this

3.1 this指向-普通函数

对于普通函数来说,谁调用,this就指向谁
在这里插入图片描述

总结

在这里插入图片描述

3.2 this指向-箭头函数

箭头函数this一层层往上找,找到最近的对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2 改变this

call

在这里插入图片描述

apply

在这里插入图片描述

    const obj = {
      age: 18
    }
    function fn(x, y) {
      console.log(this);
      console.log(x + y);
      return x + y
    }
    // 调用函数,并且让fn中的this指向了第一个参数obj
    // apply第二个参数必须放数组
    fn.apply(obj, [1, 2])

    // 本身就是在调用函数,所以返回值就是函数的返回值
    console.log(fn.apply(obj, [1, 2]));

bind

call()apply()不同的是,bind不会立即调用函数

在这里插入图片描述

    const obj = {
      age: 18
    }
    function fn() {
      console.log(this);
    }
    // bind不会调用函数
    // 可以改变this指向
    // 返回值是一个更改过this的函数
    const fun = fn.bind(obj)
    fun()

    // 需求:有一个按钮,点击里面就禁用,2秒钟后开启
    const btn = document.querySelector('button')
    btn.addEventListener('click', function () {
      // 禁用按钮
      this.disabled = true###
      setTimeout(function () {
        // 在普通函数中的话,要将this指向的window改为btn
        this.disabled = false
      }.bind(this), 2000);
    })

总结

在这里插入图片描述

4. 性能优化

4.1 防抖(debounce)

在这里插入图片描述

  <script src="lodash.js"></script>
  <script>
    // 鼠标在盒子中滑动,数字显示+1
    const box = document.querySelector('.box')
    let i = 1
    function mouseMove() {
      // 存在大量消耗性能的代码,dom操作、数据处理,可能造成卡顿
      box.innerHTML = i++
    }

    // box.addEventListener('mousemove', mouseMove)

    // 利用库函数lodash防抖函数
    // _.debounce(fun,时间)
    box.addEventListener('mousemove', _.debounce(mouseMove, 500))
  </script>

    // 手写防抖函数
    // 利用setTimeout定时器实现
    // 1. 声明定时器变量
    // 2. 每次鼠标移动的时候都要先判断是否有定时器,如果有的话先清除以前的
    // 3. 如果没有定时器,就开启定时器,存入到定时器变量中
    // 4. 定时器里面写函数调用
    function debounce(fn, t) {
      let timer
      // return 返回一个匿名函数
      return function () {
        if (timer) clearInterval(timer)
        timer = setTimeout(function () {
          fn()
        }, t)
      }
    }
    box.addEventListener('mousemove', debounce(mouseMove, 100))

4.2 节流

在这里插入图片描述

在这里插入图片描述

    // 利用节流实现性能优化
    // 鼠标在盒子中滑动,数字显示+1
    const box = document.querySelector('.box')
    let i = 1
    function mouseMove() {
      // 存在大量消耗性能的代码,dom操作、数据处理,可能造成卡顿
      box.innerHTML = i++
    }
    // 利用lodash库实现节流,500ms之后采取一次+1
    // 语法:_.throttle('mousemove'),_.throttle(mouseMove,500)
    box.addEventListener('mousemove', _.throttle(mouseMove, 3000))

总结

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值