节流 and 防抖
防抖
防抖:对于短时间内连续触发的事件,防抖的含义就是让某个时间期限内,事件处理函数只执行一次。
例子:
在第一次触发事件时,不立即执行函数,而是给出一个期限值比如 200ms ,然后:
- 如果在 200ms 内没有再次触发滚动事件,那么就执行函数
- 如果在 200ms 内再次触发滚动事件,那么当前的计时取消,重新开始计时
如果短时间内大量触发同一事件,只会执行一次函数。用去除定时器的方法。
function debounce(fn, delay) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer)
timer = setTimeout(fn, delay)
} else {
timer = setTimeout(fn, delay)
}
}
}
function showTop() {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
window.onscroll = debounce(showTop, 1000);
如果在限定时间段内,不断触发滚动事件(比如某个用户闲着无聊,按住滚动不断的拖来拖去),只要不停止触发,理论上就永远不会输出当前距离顶部的距离。
节流
如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。
function throttle(fn, delay) {
let valid = true;
return function () {
if (!valid) {
return false;
}
valid = false;
setTimeout(() => {
fn()
valid = true;
}, delay)
}
}
function showTop() {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
window.onscroll = throttle(showTop, 1000)
运行以上代码的结果是:
- 如果一直拖着滚动条进行滚动,那么会以 1s 的时间间隔,持续输出当前位置和顶部的距离。
节流还可以用时间戳实现:
function throttle(fn, delay) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > delay) {
fn.apply(context, args);
previous = now;
}
}
}
应用场景
- 搜索框input事件
- 滚动条滚动事件
页面 resize 事件,常用于需要做页面适配的时候,需要根据最终呈现的页面情况进行 dom 渲染(这种情况一般是使用防抖,因为只需要判断最后一次的变化情况)
深拷贝 and 浅拷贝
深拷贝
function deepClone(obj) {
if (typeof obj !== 'object' || obj === null) return obj;
let copy = {};
if (Array.isArray(obj)) {
copy = [];
}
for (const [key, value] of (Array.isArray(obj) ? obj.entries() : Object.entries(obj))) {
copy[key] = deepClone(value);
}
return copy;
}
浅拷贝
const extend = Object.assign || ((obj, ...args) => {
if (args.length !== 0) {
for(const source of args) {
for(const [key, value] of Object.entries(source)) {
obj[key] = value;
}
}
}
return obj;
})