防抖
记得要用timer接收啊!
今天手写的时候没有写 timer = setTimeout(),setTimeout 的返回值 timeoutID 是一个正整数,表示定时器的编号。这个值可以传递给clearTimeout() 来取消该定时器。
function debounce(func, ms = 1000) {
let timer; // 因为下一次调用debounceTask需要访问到timer,所以这里要返回一个闭包函数,携带之前的timer值
return function (...args) {
// 1.一律清除(判断是为了不清除第一次调用)
if (timer) {
clearTimeout(timer)
}
// 2.然后重新设置timer
timer = setTimeout(() => {
func.apply(this, args) // 注意:因为要传入参数所以才用了箭头函数,返回一个函数;如果不传参可以直接写成 timer = setTimeout(func, ms)
}, ms)
}
}
// 测试
const task = () => { console.log('run task') }
const debounceTask = debounce(task, 1000)
window.addEventListener('scroll', debounceTask)
节流
function throttle(func, ms = 1000) {
let canRun = true // 用一个变量记录是否正在等(和防止重复点击的思路很像)
return function (...args) {
if (!canRun) return
canRun = false // 一进来就置为不能运行
setTimeout(() => {
func.apply(this, args)
canRun = true // 计时器结束之后打开,置为可以运行
}, ms)
}
}
// 测试
const task = () => { console.log('run task') }
const throttleTask = throttle(task, 1000)
window.addEventListener('scroll', throttleTask)
深拷贝
function deepCopy(obj, cache = new WeakMap()) {
if (!obj instanceof Object) return obj
// 防止循环引用
if (cache.get(obj)) return cache.get(obj)
// 支持函数
if (obj instanceof Function) {
return function () {
return obj.apply(this, arguments)
}
}
// 支持日期
if (obj instanceof Date) return new Date(obj)
// 支持正则对象
if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags)
// 还可以增加其他对象,比如:Map, Set等,根据情况判断增加即可,面试点到为止就可以了
// 数组是 key 为数字素银的特殊对象
const res = Array.isArray(obj) ? [] : {}
// 缓存 copy 的对象,用于处理循环引用的情况
cache.set(obj, res)
// 核心:遍历对象键值对:如果是对象,递归拷贝,如果不是对象直接拷贝
Object.keys(obj).forEach((key) => {
if (obj[key] instanceof Object) {
res[key] = deepCopy(obj[key], cache)
} else {
res[key] = obj[key]
}
});
return res
}
// 测试
const source = {
name: 'Jack',
meta: {
age: 12,
birth: new Date('1997-10-10'),
ary: [1, 2, { a: 1 }],
say() {
console.log('Hello');
}
}
}
source.source = source
const newObj = deepCopy(source)
console.log(newObj.meta.ary[2] === source.meta.ary[2]); // false
console.log(newObj.meta.birth === source.meta.birth); // false
简陋方式:用json的内置方法
function deepClone(source) {
return JSON.parse(JSON.stringify(source));
}