10个常见的前端手写功能
作者:Ting Yu
链接:https://zhuanlan.zhihu.com/p/434776450
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接:https://zhuanlan.zhihu.com/p/434776450
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1.防抖:
function debounce(fn, delay) {
let timer
return function (...args) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
// 测试
const task = () => {
console.log('run task')
}
const debounceTask = debounce(task, 1000)
window.addEventListener('scroll', debounceTask)
2.节流
function throttle(fn, delay) {
let last = 0 // 上次触发时间
return (...args) => {
const now = Date.now()
if (now - last > delay) {
last = now
fn.apply(this, args)
}
}
}
// 测试
const task = () => {
console.log('run task')
}
const throttleTask = throttle(task, 1000)
window.addEventListener('scroll', throttleTask)
3.深拷贝
function deepClone(obj, cache = new WeakMap()) {
if (typeof obj !== 'object') return obj // 普通类型,直接返回
if (obj === null) return obj
if (cache.get(obj)) return cache.get(obj) // 防止循环引用,程序进入死循环
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
// 找到所属原型上的constructor,所属原型上的constructor指向当前对象的构造函数
let cloneObj = new obj.constructor()
cache.set(obj, cloneObj) // 缓存拷贝的对象,用于处理循环引用的情况
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], cache) // 递归拷贝
}
}
return cloneObj
}
// 测试
const obj = { name: 'Jack', address: { x: 100, y: 200 } }
obj.a = obj // 循环引用
const newObj = deepClone(obj)
console.log(newObj.address === obj.address) // false
4.实现Promise
class MyPromise {
constructor(executor) { // executor执行器
this.status = 'pending' // 等待状态
this.value = null // 成功或失败的参数
this.fulfilledCallbacks = [] // 成功的函数队列
this.rejectedCallbacks = [] // 失败的函数队列
const that = this
function resolve(value) { // 成功的方法
if (that.status === 'pending') {
that.status = 'resolved'
that.value = value
that.fulfilledCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法
}
}
function reject(value) { //失败的方法
if (that.status === 'pending') {
that.status = 'rejected'
that.value = value
that.rejectedCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
if (this.status === 'pending') {
// 等待状态,添加回调函数到成功的函数队列
this.fulfilledCallbacks.push(() => {
onFulfilled(this.value)
})
// 等待状态,添加回调函数到失败的函数队列
this.rejectedCallbacks.push(() => {
onRejected(this.value)
})
}
if (this.status === 'resolved') { // 支持同步调用
console.log('this', this)
onFulfilled(this.value)
}
if (this.status === 'rejected') { // 支持同步调用
onRejected