JavaScript 高级第四天

目录

深浅拷贝

浅拷贝

深拷贝

异常处理

throw抛异常

try /catch 捕获异常

debugger

处理this

改变this

性能优化

节流(throttle)

防抖(debounce)


深浅拷贝

浅拷贝

首先浅拷贝和深拷贝 只针对引用类型
浅拷贝:拷贝的是地址
常见方法:
1. 拷贝对象:Object.assgin() / 展开运算符 {...obj} 拷贝对象
2.拷贝数组:Array.prototype.concat() 或者 [...arr]

 

如果是简单数据类型 拷贝值 ,引用数据类型 拷贝的是地址 (简单理解: 如果是单层对象,没问题,如果有多层就有问题)(自己理解:对象里面在有一个对象就会有问题)
总结
1. 直接赋值和浅拷贝有什么区别?
直接赋值的方法,只要是对象,都会相互影响,因为是直接拷贝对象栈里面的地址
浅拷贝如果是一层对象,不相互影响,如果出现多层对象拷贝还会相互影响
2. 浅拷贝怎么理解?
拷贝对象之后,里面的属性值是简单数据类型直接拷贝值
如果属性值是引用数据类型则拷贝的是地址

深拷贝

深拷贝:拷贝的是对象,不是地址
常见方法:
1. 通过递归实现深拷贝
2. lodash/cloneDeep
3. 通过JSON.stringify()实现
---------------------------------------------------------
1. 通过递归实现深拷贝
函数递归:
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
简单理解: 函数内部自己调用自己, 这个函数就是递归函数
递归函数的作用和循环效果类似
由于递归很容易发生“栈溢出”错误(stack overflow),所以 必须要加退出条件 return

利用递归函数实现 setTimeout 模拟 setInterval效果

1. 通过递归函数实现深拷贝(简版)

---------------------------------------------------------
2. js库lodash里面cloneDeep内部实现了深拷贝
前提:引入js库
3. 通过JSON.stringify()实现

异常处理

了解 JavaScript 中程序异常处理的方法,提升代码运行的健壮性。

throw抛异常

异常处理是指预估代码执行过程中可能发生的错误,然后最大程度的避免错误的发生导致整个程序无法继续运行

总结:
1. throw 抛出异常信息, 程序也会终止执行
2. throw 后面跟的是错误提示信息
3. Error 对象配合 throw 使用,能够设置更详细的错误信息

try /catch 捕获异常

我们可以通过try / catch 捕获错误信息(浏览器提供的错误信息) try 试试 catch 拦住 finally 最后

总结:
1. try...catch 用于捕获错误信息
2. 将预估可能发生错误的代码写在 try 代码段中
3. 如果 try 代码段中出现错误后,会执行 catch 代码段,并截获到错误信息
4. finally 不管是否有错误,都会执行
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p>123</p>
  <script>
    function fn() {
      try {
        // 可能发送错误的代码 要写到 try
        const p = document.querySelector('.p')
        p.style.color = 'red'
      } catch (err) {
        // 拦截错误,提示浏览器提供的错误信息,但是不中断程序的执行
        console.log(err.message)
        throw new Error('你看看,选择器错误了吧')
        // 需要加return 中断程序
        // return
      }
      finally {
        // 不管你程序对不对,一定会执行的代码
        alert('弹出对话框')
      }
      console.log(11)
    }
    fn()
  </script>
</body>

</html>

debugger

我们可以通过try / catch 捕获错误信息(浏览器提供的错误信息)

处理this

this 是 JavaScript 最具“魅惑”的知识点,不同的应用场合 this 的取值可能会有意想不到的结果

普通函数的this指向
普通函数的调用方式决定了 this 的值,即【谁调用 this 的值指向谁】
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <button>点击</button>
  <script>
    // 普通函数:  谁调用我,this就指向谁
    console.log(this)  // window


    function fn() {
      console.log(this)  // window    
    }
    window.fn()



    window.setTimeout(function () {
      console.log(this) // window 
    }, 1000)



    document.querySelector('button').addEventListener('click', function () {
      console.log(this)  // 指向 button
    })


    
    const obj = {
      sayHi: function () {
        console.log(this)  // 指向 obj
      }
    }
    obj.sayHi()

  </script>
</body>

</html>
普通函数没有明确调用者时 this 值为 window, 严格模式 下没有调用者时 this 的值为 undefined

箭头函数的this指向

箭头函数中的 this 与普通函数完全不同,也不受调用方式的影响,事实上 箭头函数中并不存在this
 
1. 箭头函数会默认帮我们绑定外层 this 的值,所以在箭头函数中 this 的值和外层的 this 是一样的
2.箭头函数中的this 引用的就是最近作用域中的this
3.向外层作用域中, 一层一层查找this,直到有this的定义

注意情况1:
在开发中【使用箭头函数前需要考虑函数中 this 的值】,事件回调函数使用箭头函数时,this 为全局的 window
因此DOM事件回调函数 如果里面需要 DOM对象的this,则不推荐使用箭头函数

注意情况2:
同样由于箭头函数 this 的原因,基于原型的面向对象也不推荐采用箭头函数

总结:
1. 箭头 函数内不存在this,沿用上一级的
2.不适用
构造函数,原型函数,dom事件函数等等
3. 适用
需要使用上层this的地方
4. 使用正确的话,它会在很多地方带来方便,后面我们会大量使用慢慢体会

改变this

JavaScript 中还允许指定函数中 this 的指向,有 3 个方法可以 动态指定普通函数中 this 的指向
call()
apply()
bind()
1. call() –了解
使用 call 方法调用函数,同时指定被调用函数中 this 的值
语法:
fun.call(thisArg, arg1, arg2, ...)
thisArg: 在 fun 函数运行时指定的 this 值
arg1,arg2:传递的其他参数
返回值就是函数的返回值,因为它就是调用函数
 <script>
    const obj = {
      uname: 'pink',
      age: 21,

    }
    function fn(x, y) {
      console.log(this);
      console.log(x + y);
    }

    fn.call(obj, 1, 2)



  </script>
2. apply()-理解
使用 apply 方法调用函数,同时指定被调用函数中 this 的值
语法:
fun.apply(thisArg, [argsArray])
thisArg: 在fun函数运行时指定的 this 值
argsArray:传递的值,必须包含在 数组 里面
返回值就是函数的返回值,因为它就是调用函数
因此 apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值
求数组最大值2个方法:
1. call和apply的区别是?
都是调用函数,都能改变this指向
 参数不一样,apply传递的必须是数组,call 传递的是普通参数
3. bind()-重点
bind() 方法 不会调用函数。但是能改变函数内部this 指向
语法:
fun.bind(thisArg, arg1, arg2, ...)
thisArg:在 fun 函数运行时指定的 this 值
arg1,arg2:传递的其他参数
返回由指定的 this 值和初始化参数改造的 原函数拷贝 (新函数)
因此当我们只是想改变 this 指向,并且不想调用这个函数的时候,可以使用 bind, 比如改变定时器内部的this指向.
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <button>11111111111</button>
  <script>
    const obj = {
      age: 21

    }
    function fn() {
      console.log(this);
    }

    // const fun = fn.bind(obj)
    fn.bind(obj)()

    // fun()


    const btn = document.querySelector('button')

    btn.addEventListener("click", function () {
      this.disabled = true

      setTimeout(function () {
        this.disabled = false


      }.bind(this), 2000)
    })


  </script>
</body>

</html>
call apply bind 总结
相同点:
都可以改变函数内部的this指向.
区别点:
call 和 apply 会调用函数, 并且改变函数内部this指向.
call 和 apply 传递的参数不一样, call 传递参数 aru1, aru2..形式 apply 必须数组形式[arg]
bind 不会调用函数, 可以改变函数内部this指向.
主要应用场景:
call 调用函数并且可以传递参数
apply 经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值
bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向.

性能优化

节流(throttle)

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数
只有等到了上一个人做完核酸,整个动作完成了, 第二个人才能排队跟上
开发使用场景 – 小米 轮播图点击效果 、 鼠标移动、页面尺寸缩放resize、滚动条滚动 就可以加节流
假如一张轮播图完成切换需要300ms, 不加节流效果,快速点击,则嗖嗖嗖的切换
加上节流效果, 不管快速点击多少次, 300ms时间内,只能切换一张图片。

防抖(debounce)

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间
举个例子:
北京买房政策:需要连续5年的社保,如果中间有一年断了社保,则需要从新开始计算
比如,我 2020年开始计算,连续交5年,也就是到2024年可以买房了,包含2020年
但是我 2024年断社保了,整年没交,则需要从2025年开始算第一年往后推5年… 也就是 2029年才能买房…
1. 节流和防抖的区别是?
节流: 就是指连续触发事件但是在 n 秒中只执行一次函数,比如可以利用节流实现 1s之内 只能触发一次鼠标移动事件
防抖:如果在 n 秒内又触发了事件,则会 重新计算 函数执行时间
2. 节流和防抖的使用场景是?
节流: 鼠标移动,页面尺寸发生变化,滚动条滚动等开销比较大的情况下
防抖: 搜索框输入,设定每次输入完毕n秒后发送请求,如果期间还有输入,则从新计算时间
Lodash 库 实现节流和防抖

页面打开,可以记录上一次的视频播放位置
分析:
两个事件:
①:ontimeupdate 事件在视频/音频(audio/video)当前的播放位置发送改变时触发
②:onloadeddata 事件在当前帧的数据加载完成且还没有足够的数据播放视频/音频(audio/video)的下一帧时触发
谁需要节流?
ontimeupdate , 触发频次太高了,我们可以设定 1秒钟触发一次
思路:
1. 在ontimeupdate事件触发的时候,每隔1秒钟,就记录当前时间到本地存储
2. 下次打开页面, onloadeddata 事件触发,就可以从本地存储取出时间,让视频从取出的时间播放,如果没有就默认为0s
3. 获得当前时间 video.currentTime
答案:
  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值