JavaScript高级,ES6 笔记 第四天(防抖、节流、深拷贝,事件总线)

目录

throw

try  catch  finally

浅拷贝

深拷贝

 1、递归方式

2.loadsh

3.JSON(推荐)

call

apply

bind

 节流

 防抖

视频案例

事件总线


throw

抛出自定义错误





Please input a number between 5 and 10:

try  catch  finally

try里面放可能会出错误的代码    catch是当发生错误时执行的,且有参数,代表错误本身,finally表示不管有没有错误都会执行

JavaScript高级,ES6 笔记 第四天(防抖、节流、深拷贝,事件总线)_第1张图片


  

123

浅拷贝

浅拷贝与深拷贝都只针对  引用类型

浅拷贝拷贝的是值(其实也是地址)

    

但是这样有问题:

        const obj={
            age :18,
            obj1:{
                sex:1

            }
        }

        let o = {...obj}
        let o1={}
        Object.assign(o1,obj)
        o1.obj1.sex = 2
        console.log(o1);
        console.log(obj);//sex都为2

欠拷贝只直接拷贝最外一层的值,而对于obj1来说,最外层的值是他的地址,所以就直接把地址给了o1,改变o1时也会改变obj

深拷贝

直接拷贝对象 不是地址

JavaScript高级,ES6 笔记 第四天(防抖、节流、深拷贝,事件总线)_第2张图片

 1、递归方式

设置函数,当originValue里面还有引用数据类型时,再次调用自己,只是将originValue改为里面的引用数据类型

    

这里比较难的地方在于    obj.self = obj  ,也就是在obj中创造了self指向自己

在深拷贝时,传入map = new WeakMap()用于记录已经生成的应用对象,当拷贝到self时,这个时候又需要创造一个obj对象,这时可以将map中存储好的obj直接拿出来赋值给它

2.loadsh

先去下载库,并引入js

Lodash 简介 | Lodash 中文文档 | Lodash 中文网

调用cloneDeep()

        var oo = _.cloneDeep(obj)
        console.log(oo);

3.JSON(推荐)

JSON 语法 | 菜鸟教程

    

但是JSON有个问题,如果 对象有  函数  或者  symbol  则无法解析

call

可以改变this指向,在调用的时候用,第一个值就是设置指向

        let obj={

        }

        function fn(x,y){
            console.log(this);
        }
        fn.call(obj,1,2)//obj

apply

也是改变this指向 ,类似,传参必须为数组,这个用的比较多

        let obj={
        }
        function fn(x,y){
            console.log(this);//obj
            console.log(x+y);//3
        }
        fn.apply(obj,[1,2])

值得注意的是,当不匹配时:

        let obj={

        }

        function fn(x){
            console.log(this);//obj
            console.log(x);//1
        }
        fn.apply(obj,[1,2])

不会将数组全部传入

提供了另外一种求最大值的方式

        let aa = [1,4,5,8,9]
        //Math.max(1,4,7,98)

        console.log(Math.max(...aa));
        console.log(Math.max.apply(null,aa));

bind

前面两种都必须要调用函数,这个不需要,返回值是函数,其实就是改变原函数的this得到了一个新函数

        let aa = [1,4,5,8,9]
        function fn(){
            console.log(this);
        }
        fn.bind(null)//无输出

        let fun = fn.bind(aa);
        fun()//a

小应用,点击按钮禁用,两秒开启

    
    

这个地方把定时器的this改为了btn,因为bind(this)里面这个this还是btn

JavaScript高级,ES6 笔记 第四天(防抖、节流、深拷贝,事件总线)_第3张图片

 节流

在一定的时间内只能执行一次,不管触发了多少次,在这个时间内只执行一次

JavaScript高级,ES6 笔记 第四天(防抖、节流、深拷贝,事件总线)_第4张图片JavaScript高级,ES6 笔记 第四天(防抖、节流、深拷贝,事件总线)_第5张图片

例子:div滑动时,200ms内只改变span一次

        var start = 0

        document.querySelector('div').addEventListener('mousemove',function(){
            let now = Date.now()
            if(now-start>=200){
                    document.querySelector('span').innerHTML =i++
                    start = now
                }

        })

每次调用函数时都将此时的时间赋给now,当now与start差别大于200毫秒时才会改变i,然后将现在的时间赋给start以进行下次函数

上面用的是时间差值的方法,也可以采用定时器的方法

这里再加了一个immediate 变量,具体原理参照  防抖


  
  

  

  

 防抖

触发后n秒内只执行一次,但是如果这段时间内还触发了,则会重新计算时间

也就是说,在一定时间内我不停的进行高速的事件触发,但是只会在最后一次触发结束后进行执行

JavaScript高级,ES6 笔记 第四天(防抖、节流、深拷贝,事件总线)_第6张图片

应用场景:输入框,一般是等我输入完了才会去匹配

例子:在div滑动时 停下来一秒钟才会改变span

        document.querySelector('div').addEventListener('mousemove',function(){
            if(timeget) clearTimeout(timeget)
            timeget = setTimeout(function(){
                document.querySelector('span').innerHTML =i++

            },1000)
        })

例子:再次采用函数实现,需求是对输入框,输入结束一段时间后反应,这里还提供了应该取消接口,可以在这段时间结束前 结束响应

    
    

    

再加一个立即执行功能,即在输入时,第一次输入马上响应,后面输入则等待一段时间,然后再次输入又马上响应

        let mydebounce = function(fn,delay,immediate=false){
            let timeout = null 
            let immediate_done = false
            let _debounce = function(){
                if(timeout) clearTimeout(timeout)
                if(!immediate_done && immediate){
                    fn.apply(this)
                    immediate_done = true
                    return
                }
                timeout = setTimeout(()=>{
                    fn.apply(this)
                    immediate_done = false
                },delay)
            }
            _debounce.cancel = function(){
                if(timeout) clearTimeout(timeout)
                immediate_done = false
            }
            return _debounce
        }

定义了 immediate表示是否需要这个功能,immediate_done判断是否完成,当输入时,immediate为1,immediate_done为0时,会马上执行fn函数,然后使得immediate_done为1。在执行完时间间隔后,又将immediate_done为0

还可以将_debounce函数返回为promise,好处是在fn传入时有返回值的情况下,可以拿到这个返回值

      let res = null
      let _debounce = function () {
        return new Promise((resolve, reject)=>{
          if (timeout) clearTimeout(timeout)
          if (!immediate_done && immediate) {
            res = fn.apply(this)
            resolve(res)
            immediate_done = true
            return
          }

          timeout = setTimeout(() => {
            res = fn.apply(this)
            resolve(res)
            immediate_done = false
          }, delay)
        })
      }

 若fn有返回值,就可以通过.then得到

    let ipt = document.querySelector('input')
    let btn = document.querySelector('button')

    let debounce = mydebounce(function () {
      console.log(this.value);
      return(111)
    }, 1000)


    ipt.addEventListener('input', debounce)
    btn.addEventListener('click', debounce.cancel)

    debounce().then(res=>{
      console.log(res);
    })

JavaScript高级,ES6 笔记 第四天(防抖、节流、深拷贝,事件总线)_第7张图片

 还可以使用lodash

节流

_.throttle(fn,300)

在300ms内只能执行一次fn函数

        function fn(){
            document.querySelector('span').innerHTML =i++
        }
        document.querySelector('div').addEventListener('mousemove',_.throttle(fn,300))

        

 防抖

 _.debounce(fn,300)

停下来300ms后才执行fn函数

        function fn(){
            document.querySelector('span').innerHTML =i++
        }
        document.querySelector('div').addEventListener('mousemove',_.debounce(fn,300))

视频案例

    const video = document.querySelector('video')
    video.onloadeddata = function(){
        video.currentTime  = localStorage.getItem('time')||0
    }
    video.ontimeupdate = _.throttle(function(){
        localStorage.setItem('time',video.currentTime)
    },1000)

得到video视频

每次打开页面都把存储中的time拿出来,赋值给视频的currentTime,即跳转到对应的时间

视频的时间发生改变时,添加防抖,每隔1s更新存储中的time值

实现每次页面打开可以返回上次视频播放的地方

事件总线

当项目中有很多组件,很多文件,当一个文件中的某一个事件触发,希望另外一个文件得到响应,就需要用到事件总线

这里我们自己用js实现

一般来说这个事件总线是一个对象,里面有emit函数,用于发送时间,也有on函数,用于接受事件

  
  

因为on函数,对于一种事件的响应函数可能不止一个,所以需要eventMap来存储函数,其数据结构为{ eventname:[fn1,fn2]}

在emit时,先取得事件对应的函数数组,再以此执行

还可以写一个删除函数函数

      off(eventname,fn){
        let fns = this.eventMap[eventname]
        if (!fns) return
        for(let i=0;i

你可能感兴趣的:(前端,javascript,es6,前端)