记录自己一些熟视无睹的手写Js

202 阅读4分钟

记录自己一些熟视无睹的手写Js

我经常在想一个问题,我真的熟悉js了吗?高阶函数、闭包、原型链......,这些如果碰到的话多多少少可以说出来。但是当我听到一些有关js的手写题目的时候,比如:防抖、节流、数组去重、数组扁平化等,脑子里经常就一句话:这些我知道,我知道怎么实现,那些原理也就那样。但是如果真的要我去手写实现的时候,我可能就是那个一直在写bug的人。这篇文章就是记录一下我学习这些手写js的过程和一些自己的理解吧。

数组去重

代码实现

  const arr = [1,2,2,3,3,4,4]
        function uniqueArr(arr) {
            return [...new Set(arr)]
        }
        console.log(uniqueArr(arr));

个人理解

嗷!熟悉es6的掘友们相信一下子就看出来了,这种实现方式主要是利用了set数据类型自动去重,然后用扩展运算符将已经转化成的set再次转化成数据类型

数组扁平化(递归版)

代码实现

 const arr = [1,[2,3,4],5,[2,[2]]]
 function flatter(arr) {
       if(!arr.length) return []
       return arr.reduce((pre,cur) => Array.isArray(cur) ? [...pre,...flatter(cur)] : [...pre,cur],[])
        }
        console.log(flatter(arr));

个人理解

  • 首先,判断数组的长度,也就是判断该数组是不是空数组,如果是空数组则直接返回一个空数组。
  • 然后根据数组的reduce方法进行操作(其实如果感兴趣的话也可以手写一下reduce,如果不懂reduce的话自己先去了解,咳咳)。这串代码的意思是:判断一下cur是不是数组,如果是的话就递归,如果不是的话,就把curpre拼接在一起。

数组扁平化(迭代版)

代码实现

 const arr = [1,[2,3,4],5,[2,[2]]]
 function flatter(arr) {
    if(!arr.length) return []
    while(arr.some((item) => Array.isArray(item))){
        arr = [].concat(...arr)
     }
     return arr
    }
    console.log(flatter(arr));

个人理解

这种写法就相对的简单粗暴了,使用数组的some方法,遍历判断数组中是否含有数组,有的话,直接扩展运算符展开与空数组连接。

手写new

代码实现

  function myNew(fn, ...args) {
        let obj = Object.create(fn.prototype); // 创建了一个新的空对象
        let res = fn.call(obj, ...args); // 设置原型,将对象的原型设置为函数的prototype对象
        if (res && (typeof res === "object" || typeof res === "function")) {
          // 返回对象
          return res;
        }
        return obj;
      }

个人理解

  • 首先创建了一个新的 空对象
  • 设置原型,将对象的原型设置为函数的prototype对象
  • 让函数的 this指向这个对象,执行构造函数的代码(为这个新对象添加属性)
  • 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象

节流

什么是节流

  • 节流是指当时间触发时,会触发一个事件的响应函数。
  • 但是该事件如果被频繁触发,那么 节流函数会按照一定的频率来执行函数
  • 节流类似于技能cd,不管你按了几次,必须等到cd结束后才能释放技能。也就是说如果在cd事件段,不管你触发了几次事件,只会执行一次。当下一次cd好了只会,才会再次执行

代码实现

// interval 间隔时间,也就是cd的长短
function thorttle(fn,wait) {
    let timer;
    return function() {
        let _this = this
        let args = arguments
        
        if(!timer) {
            timer = setTimeout(() => {
                timer = null;
                fn.apply(_this,args)
            },wait)
        }
    }
}

个人理解

嗷!乍一看还挺麻烦的,运用了闭包、高阶函数、apply这些比较晦涩难懂的东西,但是我觉得这串简易节流的核心主要是 timer节流阀,然后按照一定的频率触发即 定时器

防抖

什么是防抖

简而言之,防抖就是将函数的执行延迟一定时间,如果在该时间内重新触发事件,那么延迟的时间就会重置,只有真正到达了延迟时间,才会执行回调函数。

代码实现

function debounce(fn, wait) {
        let timer;
        return function () {
          let _this = this;
          let args = arguments;
          if (timer) {
            clearTimeout(timer);
          }
          timer = setTimeout(function () {
            fn.apply(_this, args);
          }, wait);
        };
      }

个人理解

防抖和节流的代码设计的区别其实挺微妙的,但是因为这点区别却能在不同的应用场景中满足需求,嗷,好好体会吧!各位!

待续