JavaScript进阶--节流防抖以及技巧打磨

打磨技巧

深浅拷贝

只针对引用类型

浅拷贝

拷贝的是值,但引用数据类型的值为地址

方法:

  • Object.assign(newobj,oldobj)
  • Array.concat(newArr,oldArr)

配合展开运算符...

比较复制

复制相当于把将要复制对象的地址,直接进行获取,而不是创建一个新的对象,赋予属性的值和名

 //实现效果分隔线函数
    const cut = () => { console.log("--------"); }
    //复制
    const obj = {
      name: 'jason',
      age: 18,
      family: {
        baby: 'small jason'
      }
    }
    const o = obj;
    //若改变o中属性的值,obj的属性值也会发生改变
    o.age = 20;
    console.log(o.age);
    console.log(obj.age);
    cut();

    //浅拷贝assign
    const obj1 = { ...obj };
    obj1.age = 19;
    //若更改了里面第二层及以上的内容,原来拷贝的对象中的内容也会发生改变
    obj1.family.baby = 'tall jason';
    console.log(obj1.family);
    console.log(obj.family);
    console.log(obj1.age);
    console.log(obj.age);
    cut();
    //浅拷贝concat
    const a = [1, 2, 3];
    const b = [1, 2, 3, [1, 2, 3]];
    const a1 = [...a];
    const b1 = [...b];
    a1[2] = 4;
    console.log(a[2]);
    console.log(a1[2]);
    b1[3][1] = 4;
    //若更改了里面第二层及以上的内容,原来拷贝的对象中的内容也会发生改变
    console.log(b[3][1]);
    console.log(b1[3][1]);
    cut();
深拷贝

三种方法

  • 递归实现
  • lodashcloneDeep(obj)
  • 利用JSON转化为字符串再转换为对象进行完成

递归实现

先复习递归函数

在函数体中调用自身,并带有条件退出函数的函数

小案例

 function getTime() {
      document.querySelector('div').innerHTML = new Date().toLocaleString();
      setTimeout(getTime, 1000);
    }
    getTime();

三种方法的实现

//定义输出分隔线函数
    function cut() {
      console.log("-------------------");
    }
    //1.递归函数实现
    const obj = {
      name: 'jason',
      age: 28,
      family: {
        baby: "small jason",
        toy: ['car', 'pani']
      }
    }
    const obj1 = {};
    function deepcopy(newobj, oldobj) {
      for (let k in oldobj) {
        //判断当前的属性值是否为数组或者对象,是则进行递归调用,换其他参数
        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 {
          //相当于浅拷贝
          newobj[k] = oldobj[k];
        }
      }
    }
    //调用深拷贝函数
    deepcopy(obj1, obj);
    obj1.family.baby = 'tall jason';
    obj1.family.toy[1] = 'plane';
    console.log(obj1.family);
    console.log(obj.family);
    cut();

    //2.lodash中的deepcopy()方法


    const obj2 = _.cloneDeep(obj);
    obj2.family.baby = 'tall jason';
    obj2.family.toy[1] = 'plane';
    console.log(obj2.family);
    console.log(obj.family);
    cut();
    //3.JSON字符串再转换为对象,开辟一个新的对象
    const obj3 = JSON.parse(JSON.stringify(obj));
    obj3.family.baby = 'tall jason';
    obj3.family.toy[1] = 'plane';
    console.log(obj3.family);
    console.log(obj.family);

第二种方法需要有lodash的文件

异常处理

try catch finally throw

try中包含的是要检查是否有异常的代码,catch中为抓取异常后的操作,finally为无论如何都会执行的代码

throw用于在函数体中应有的异常,或者是一些常见异常的抛出

 const noHave = new Error('参数不能为空孩子');
    function add(x, y) {
      if (!x || !y) {
        throw noHave;
      }
      console.log(x - (-y));

    }
    let x = 1;
    let y = 2;
    try {
      add(x);
      add(y);
      add(x, y);
    } catch (noHave) {
      alert('你应该重新输入两个参数')
      x = prompt('输入x');
      y = prompt('输入y');
      add(x, y);
    } finally {
      console.log('你的函数总该运行成功了把');

    }

this指向

  • 普通函数谁调用就指向谁

  • 箭头函数并不存在this

    默认绑定外层的this,若外层没有,则向更外层进行寻找,都找不到,默认为window

  //1.普通函数
    console.log(this);
    setTimeout(function () {
      console.log(this);
    }, 1000)
    const obj = {
      name: 'jason',
      play: function () {
        console.log(this);
      }
    }
    obj.play();

    //2.箭头函数
    const obj1 = {
      name: 'jason',
      play: () => {
        console.log(this); //windows
      }
    }
    const btn = document.querySelector('button')
    btn.addEventListener('click', () => {
      console.log(this);

    })

改变this指向

  • call()
  • apply()
  • bind()
//call(this,其他参数)
    function fn(x, y) {
      console.log(this);
      console.log(x + y);

    }
    const obj = {
      name: 'jason'
    }
    // fn();
    fn.call(obj, 1, 2);
    //apply(this,[其他参数])
    const obj1 = {
      name: 'Jason'
    }
    const a = [1, 2];
    fn.apply(obj1, a);

    //bind(this) 不调用函数,返回一个函数,改变了this指向
    const obj2 = {
      name: 'biber'
    }
    const fn1 = fn.bind(obj2);
    fn1(1, 2);

防抖(debounce)

单位时间内,频繁触发事件,只执行最后一次

如王者回城,搜索框,及手机号验证输入 ==> 提高性能,减少服务端请求压力

在这里插入图片描述

实现:

  • lodash提供的防抖函数
  • 手搓一个出来
let i = 0;

    function mouseMove() {
      i++;
      box.innerHTML = i;
    }
    const box = document.querySelector('.box');
    box.innerHTML = i;
    box.addEventListener('mousemove', _.debounce(mouseMove, 500))
  let i = 0; //盒子里面的变量
    const box = document.querySelector('.box');
    box.innerHTML = i;
    function mousemove() {
      i++;
      box.innerHTML = i;
    }
    function debounce(fn, t) {
      let timer;
      //使用函数来作为返回,使用了闭包,timer只可以被返回后的函数修改,外界无法修改timer
      return function () {
        if (timer) {
          clearTimeout(timer);
        }
        timer = setTimeout(fn, t);
      }
    }
    box.addEventListener('mousemove', debounce(mousemove, 300));

节流 throttle

单位时间内,频繁触发事件,只执行一次

如王者技能冷却

在这里插入图片描述

实现:

  • lodash提供的节流函数
  • 手搓一个
 const box = document.querySelector('.box');
    let i = 0;
    box.innerHTML = i;
    function mousemove() {
      i++;
      box.innerHTML = i;
    }
    box.addEventListener('mousemove', _.throttle(mousemove, 500));
 const box = document.querySelector('.box');
    let i = 0;
    box.innerHTML = i;
    function mousemove() {
      i++;
      box.innerHTML = i;
    }
    function throttle(fn, t) {
      let timer = null;
      return function () {
        if (!timer) {
          timer = setTimeout(function () {
            mousemove();
            //清空定时器 不用clearTimeout 因为定时器仍在工作,无法通过此方法进行清除
            timer = null;
          }, 500)
        }
      }
    }
    box.addEventListener('mousemove', throttle(mousemove, 500));

节流综合案例

视频播放时,通过节流每秒记录一次数据到本地存储,刷新页面后,将本地存储的播放时间位置赋给视频的当前时间的属性(要考虑第一次刷新页面时,没有数据在本地存储中)

 const video = document.querySelector('video');
    video.ontimeupdate = _.throttle(function () {
      localStorage.setItem('currentTime', video.currentTime);
    }, 1000)
    video.onloadeddata = function () {
      video.currentTime = localStorage.getItem('currentTime') || 0; //逻辑中断,若前面为真,则后面的0赋值不会执行
    }
上一篇:【MATLAB问题及需求收集】关于往期算法问题收集/新需求收集


下一篇:注册安全分析报告:北外网校