一、防抖debounce
- 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间
- 当事件密集触发时,函数的触发会被频繁的推迟
- 只有等待了一段时间也没有事件触发,才会真正的执行响应函数
应用场景
- 输入框中频繁的输入内容,搜索或者提交信息
- 频繁的点击按钮,触发某个事件
- 监听浏览器滚动事件,完成某些特定操作
- 用户缩放浏览器的resize事件
二、节流throttle
- 当事件触发时,会执行这个事件的响应函数
- 如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数
- 不管在这个中间有多少次触发这个事件,执行函数的频繁总是固定的
应用场景
- 监听页面的滚动事件
- 鼠标移动事件
- 用户频繁点击按钮操作
- 游戏中的一些设计
三、防抖函数实现
简易版
如果是一个一般的面试,你可以就写个简易版的能实现要求就行
function debounce(fn, delay = 500) {
let timer = null
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay);
}
return _debounce
}
加强版
- 添加是否立即执行(每个阶段开始时都先执行一次)
- 添加取消功能
- 处理返回值
function debounce(fn, delay = 500, immediate = false, callback = null) {
let timer = null
// 是否有立即执行过
let isInvoke = false
const _debounce = function (...args) {
if (timer) clearTimeout(timer)
if (immediate && !isInvoke) {
const result = fn.apply(this, args)
if (callback) callback(result)
isInvoke = true
} else {
timer = setTimeout(() => {
const result = fn.apply(this, args)
if (callback) callback(result)
isInvoke = false
}, delay);
}
}
// 取消功能
_debounce.cancel = function() {
if (timer) clearTimeout(timer)
}
return _debounce
}
四、节流函数实现
简易版
function throttle(fn, interval = 1000) {
let lastTime = 0
const _throttle = function(...args) {
const nowTime = new Date().getTime()
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
fn.apply(this, args)
lastTime = nowTime
}
}
return _throttle
}
加强版
// leading 第一次是否执行 trailing 尾部是否执行
function throttle(fn, interval = 1000, options = { leading: true, trailing: false, callback: null }) {
const { leading, trailing, callback } = options
let lastTime = 0
let timer = null
const _throttle = function(...args) {
const nowTime = new Date().getTime()
// 第一次是否执行判断
if (!leading && !lastTime) lastTime = nowTime
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
const result = fn.apply(this, args)
if (callback) callback(result)
lastTime = nowTime
return
}
// 尾部是否执行
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
lastTime = !leading ? 0 : new Date().getTime()
const result = fn.apply(this, args)
if (callback) callback(result)
}, remainTime);
}
// 取消
_throttle.cancel = function() {
if (timer) clearTimeout(timer)
timer = null
lastTime = 0
}
}
return _throttle
}
五、深拷贝实现
简易版
function deepClone(originValue) {
const originValueType = typeof originValue
if (originValueType === 'function') return originValue
if (originValue === null || originValueType !== 'object') return originValue
const newObject = Array.isArray(originValue) ? [] : {}
for (const key in originValue) {
newObject[key] = deepClone(originValue[key])
}
return newObject
}
加强版
- 添加Symbol为key,或者值的处理
- 添加set处理
- 添加Map处理
- 添加循环引用处理
function deepClone(originValue, map = new WeakMap()) {
// Set类型处理
if (originValue instanceof Set) return new Set([...originValue])
// Map类型处理
if (originValue instanceof Map) return new Map([...originValue])
const originValueType = typeof originValue
// Symbol处理 如果值是Symbol,重新创建一个Symbol
if (originValueType === 'symbol') return Symbol(originValue.description)
// 函数处理
if (originValueType === 'function') return originValue
// 非对象类型处理
if (originValue === null || originValueType !== 'object') return originValue
// 处理循环引用
if (map.has(originValue)) return map.get(originValue)
const newObject = Array.isArray(originValue) ? [] : {}
// 处理循环引用
map.set(originValue, newObject)
for (const key in originValue) {
newObject[key] = deepClone(originValue[key], map)
}
// 对key是Symbol的特殊处理
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for (const sKey of symbolKeys) {
newObject[sKey] = deepClone(originValue[sKey], map)
}
return newObject
}