十个常见的前端手写功能,你全都会吗?

开发 前端
万丈高楼平地起,地基打的牢,才能永远立于不败之地。今天给大家带来的是10个常见的 JavaScript 手写功能,重要的地方已添加注释。有的是借鉴别人的,有的是自己写的,如有不正确的地方,欢迎多多指正。

万丈高楼平地起,地基打的牢,才能永远立于不败之地。今天给大家带来的是10个常见的 JavaScript 手写功能,重要的地方已添加注释。有的是借鉴别人的,有的是自己写的,如有不正确的地方,欢迎多多指正。

[[440884]]

1、防抖

 

  1. function debounce(fn, delay) { 
  2.   let timer 
  3.   return function (...args) { 
  4.     if (timer) { 
  5.       clearTimeout(timer) 
  6.     } 
  7.     timer = setTimeout(() => { 
  8.       fn.apply(this, args) 
  9.     }, delay) 
  10.   } 
  11.  
  12. // 测试 
  13. function task() { 
  14.   console.log('run task'
  15. const debounceTask = debounce(task, 1000) 
  16. window.addEventListener('scroll', debounceTask) 

 

2、节流

 

  1. function throttle(fn, delay) { 
  2.   let last = 0 // 上次触发时间 
  3.   return (...args) => { 
  4.     const now = Date.now() 
  5.     if (now - last > delay) { 
  6.       last = now 
  7.       fn.apply(this, args) 
  8.     } 
  9.   } 
  10.  
  11. // 测试 
  12. function task() { 
  13.   console.log('run task'
  14. const throttleTask = throttle(task, 1000) 
  15. window.addEventListener('scroll', throttleTask) 

 

3、深拷贝

 

  1. function deepClone(obj, cache = new WeakMap()) { 
  2.   if (typeof obj !== 'object'return obj // 普通类型,直接返回 
  3.   if (obj === nullreturn obj 
  4.   if (cache.get(obj)) return cache.get(obj) // 防止循环引用,程序进入死循环 
  5.   if (obj instanceof Datereturn new Date(obj) 
  6.   if (obj instanceof RegExp) return new RegExp(obj) 
  7.    
  8.   // 找到所属原型上的constructor,所属原型上的constructor指向当前对象的构造函数 
  9.   let cloneObj = new obj.constructor() 
  10.   cache.set(obj, cloneObj) // 缓存拷贝的对象,用于处理循环引用的情况 
  11.   for (let key in obj) { 
  12.     if (obj.hasOwnProperty(key)) { 
  13.       cloneObj[key] = deepClone(obj[key], cache) // 递归拷贝 
  14.     } 
  15.   } 
  16.   return cloneObj 
  17.  
  18. // 测试 
  19. const obj = { name'Jack', address: { x: 100, y: 200 } } 
  20. obj.a = obj // 循环引用 
  21. const newObj = deepClone(obj) 
  22. console.log(newObj.address === obj.address) // false 

 

4、实现 Promise

 

  1. class MyPromise { 
  2.   constructor(executor) { // executor执行器 
  3.     this.status = 'pending' // 等待状态 
  4.     this.value = null // 成功或失败的参数 
  5.     this.fulfilledCallbacks = [] // 成功的函数队列 
  6.     this.rejectedCallbacks = [] // 失败的函数队列 
  7.     const that = this 
  8.     function resolve(value) { // 成功的方法 
  9.       if (that.status === 'pending') { 
  10.         that.status = 'resolved' 
  11.         that.value = value 
  12.         that.fulfilledCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法 
  13.       } 
  14.     } 
  15.     function reject(value) { //失败的方法 
  16.       if (that.status === 'pending') { 
  17.         that.status = 'rejected' 
  18.         that.value = value 
  19.         that.rejectedCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法 
  20.       } 
  21.     } 
  22.     try { 
  23.       executor(resolve, reject) 
  24.     } catch (err) { 
  25.       reject(err) 
  26.     } 
  27.   } 
  28.   then(onFulfilled, onRejected) { 
  29.     if (this.status === 'pending') { 
  30.       // 等待状态,添加回调函数到成功的函数队列 
  31.       this.fulfilledCallbacks.push(() => { 
  32.         onFulfilled(this.value) 
  33.       }) 
  34.       // 等待状态,添加回调函数到失败的函数队列 
  35.       this.rejectedCallbacks.push(() => { 
  36.         onRejected(this.value) 
  37.       }) 
  38.     } 
  39.     if (this.status === 'resolved') { // 支持同步调用 
  40.       console.log('this', this) 
  41.       onFulfilled(this.value) 
  42.     } 
  43.     if (this.status === 'rejected') { // 支持同步调用 
  44.       onRejected(this.value) 
  45.     } 
  46.   } 
  47.  
  48. // 测试 
  49. function fn() { 
  50.   return new MyPromise((resolve, reject) => { 
  51.     setTimeout(() => { 
  52.       if(Math.random() > 0.6) { 
  53.         resolve(1) 
  54.       } else { 
  55.         reject(2) 
  56.       } 
  57.     }, 1000) 
  58.   }) 
  59. fn().then
  60.   res => { 
  61.     console.log('res', res) // res 1 
  62.   }, 
  63.   err => { 
  64.     console.log('err', err) // err 2 
  65.   }) 

 

5、异步控制并发数

 

  1. function limitRequest(urls = [], limit = 3) { 
  2.   return new Promise((resolve, reject) => { 
  3.     const len = urls.length 
  4.     let count = 0 // 当前进行到第几个任务 
  5.  
  6.     const start = async () => { 
  7.       const url = urls.shift() // 从数组中拿取第一个任务 
  8.       if (url) { 
  9.         try { 
  10.           await axios.post(url) 
  11.           if (count == len - 1) { 
  12.             // 最后一个任务成功 
  13.             resolve() 
  14.           } else { 
  15.             count++ 
  16.             // 成功,启动下一个任务 
  17.             start() 
  18.           } 
  19.         } catch (e) { 
  20.           if (count == len - 1) { 
  21.             // 最后一个任务失败 
  22.             resolve() 
  23.           } else { 
  24.             count++ 
  25.             // 失败,启动下一个任务 
  26.             start() 
  27.           } 
  28.         } 
  29.       } 
  30.     } 
  31.  
  32.     // 启动limit个任务 
  33.     while (limit > 0) { 
  34.       start() 
  35.       limit -= 1 
  36.     } 
  37.   }) 
  38.  
  39. // 测试 
  40. limitRequest(['http://xxa''http://xxb''http://xxc''http://xxd''http://xxe']) 

 

6、ES5继承(寄生组合继承)

 

  1. function Parent(name) { 
  2.   this.name = name 
  3. Parent.prototype.eat = function () { 
  4.   console.log(this.name + ' is eating'
  5.  
  6. function Child(name, age) { 
  7.   Parent.call(this, name
  8.   this.age = age 
  9. Child.prototype = Object.create(Parent.prototype) 
  10. Child.prototype.contructor = Child 
  11. Child.prototype.study = function () { 
  12.   console.log(this.name + ' is studying'
  13.  
  14. // 测试 
  15. let child = new Child('xiaoming', 16) 
  16. console.log(child.name) // xiaoming 
  17. child.eat() // xiaoming is eating 
  18. child.study() // xiaoming is studying 

 

7、数组排序

sort 排序

 

  1. // 对数字进行排序,简写 
  2. const arr = [3, 2, 4, 1, 5] 
  3. arr.sort((a, b) => a - b) 
  4. console.log(arr) // [1, 2, 3, 4, 5] 
  5.  
  6. // 对字母进行排序,简写 
  7. const arr = ['b''c''a''e''d'
  8. arr.sort() 
  9. console.log(arr) // ['a''b''c''d''e' 

 

冒泡排序

 

  1. function bubbleSort(arr) { 
  2.   let len = arr.length 
  3.   for (let i = 0; i < len - 1; i++) { 
  4.     // 从第一个元素开始,比较相邻的两个元素,前者大就交换位置 
  5.     for (let j = 0; j < len - 1 - i; j++) { 
  6.       if (arr[j] > arr[j + 1]) { 
  7.         let num = arr[j] 
  8.         arr[j] = arr[j + 1] 
  9.         arr[j + 1] = num 
  10.       } 
  11.     } 
  12.     // 每次遍历结束,都能找到一个最大值,放在数组最后 
  13.   } 
  14.   return arr 
  15.  
  16. //测试 
  17. console.log(bubbleSort([2, 3, 1, 5, 4])) // [1, 2, 3, 4, 5] 

 

8、数组去重

Set 去重

 

  1. cosnt newArr = [...new Set(arr)]  

 

Array.from 去重

 

  1. const newArr = Array.from(new Set(arr)) 

indexOf 去重

 

  1. function resetArr(arr) { 
  2.   let res = [] 
  3.   arr.forEach(item => { 
  4.     if (res.indexOf(item) === -1) { 
  5.       res.push(item) 
  6.     } 
  7.   }) 
  8.   return res 
  9.  
  10. // 测试 
  11. const arr = [1, 1, 2, 3, 3] 
  12. console.log(resetArr(arr)) // [1, 2, 3] 

 

9、获取 url 参数

URLSearchParams 方法

 

  1. // 创建一个URLSearchParams实例 
  2. const urlSearchParams = new URLSearchParams(window.location.search); 
  3. // 把键值对列表转换为一个对象 
  4. const params = Object.fromEntries(urlSearchParams.entries()); 

 

split 方法

 

  1. function getParams(url) { 
  2.   const res = {} 
  3.   if (url.includes('?')) { 
  4.     const str = url.split('?')[1] 
  5.     const arr = str.split('&'
  6.     arr.forEach(item => { 
  7.       const key = item.split('=')[0] 
  8.       const val = item.split('=')[1] 
  9.       res[key] = decodeURIComponent(val) // 解码 
  10.     }) 
  11.   } 
  12.   return res 
  13.  
  14. // 测试 
  15. const user = getParams('http://www.baidu.com?user=%E9%98%BF%E9%A3%9E&age=16'
  16. console.log(user) // { user'阿飞', age: '16' } 

 

10、事件总线 | 发布订阅模式

 

  1. class EventEmitter { 
  2.   constructor() { 
  3.     this.cache = {} 
  4.   } 
  5.  
  6.   on(name, fn) { 
  7.     if (this.cache[name]) { 
  8.       this.cache[name].push(fn) 
  9.     } else { 
  10.       this.cache[name] = [fn] 
  11.     } 
  12.   } 
  13.  
  14.   off(name, fn) { 
  15.     const tasks = this.cache[name
  16.     if (tasks) { 
  17.       const index = tasks.findIndex((f) => f === fn || f.callback === fn) 
  18.       if (index >= 0) { 
  19.         tasks.splice(index, 1) 
  20.       } 
  21.     } 
  22.   } 
  23.  
  24.   emit(name, once = false) { 
  25.     if (this.cache[name]) { 
  26.       // 创建副本,如果回调函数内继续注册相同事件,会造成死循环 
  27.       const tasks = this.cache[name].slice() 
  28.       for (let fn of tasks) { 
  29.         fn(); 
  30.       } 
  31.       if (once) { 
  32.         delete this.cache[name
  33.       } 
  34.     } 
  35.   } 
  36.  
  37. // 测试 
  38. const eventBus = new EventEmitter() 
  39. const task1 = () => { console.log('task1'); } 
  40. const task2 = () => { console.log('task2'); } 
  41.  
  42. eventBus.on('task', task1) 
  43. eventBus.on('task', task2) 
  44. eventBus.off('task', task1) 
  45. setTimeout(() => { 
  46.   eventBus.emit('task') // task2 
  47. }, 1000) 

 

 

以上就是工作或求职中最常见的手写功能,你是不是全都掌握了呢

 

责任编辑:华轩 来源: 今日头条
相关推荐

2023-07-14 11:36:09

GPT-4社交

2023-12-15 10:42:05

2022-11-25 14:55:43

JavaScriptweb应用程序

2023-05-28 22:48:29

程序员编程

2022-07-31 23:54:24

Linux操作系统

2022-06-06 16:40:20

工作流程效率管理

2022-07-31 23:53:37

Linux操作系统设备

2023-12-22 16:48:00

Kubernetes容器集群

2022-01-05 11:40:36

Go特性语言

2019-04-01 06:37:12

R语言数据分析数据

2010-03-04 16:09:09

2020-03-25 10:27:59

Python语言

2023-12-27 14:12:40

JavaScrip技巧

2023-07-14 14:25:00

Python语言错误

2024-09-24 07:57:55

SQL错误​​EXPLAIN​

2022-05-16 07:48:54

Python操作类型

2023-07-14 10:53:00

开源前端

2022-06-08 23:45:44

iOS苹果功能

2023-12-07 08:02:48

document前端JavaScript
点赞
收藏

51CTO技术栈公众号