记录自己一些熟视无睹的手写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是不是数组,如果是的话就递归,如果不是的话,就把cur和pre拼接在一起。
数组扁平化(迭代版)
代码实现
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);
};
}
个人理解
防抖和节流的代码设计的区别其实挺微妙的,但是因为这点区别却能在不同的应用场景中满足需求,嗷,好好体会吧!各位!