一、深拷贝 (Deep Copy)
什么是深拷贝?
深拷贝是指创建一个新对象,完全复制原始对象的所有属性,包括嵌套对象和数组,使得新对象与原始对象完全独立,修改新对象不会影响原始对象。
实现深拷贝的方法
1. JSON 方法(简单但有局限)
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
局限:
- 无法处理函数、Symbol、undefined
- 无法处理循环引用
- 会忽略对象的原型链
- Date 对象会变成字符串
2. 递归实现(完整版)
function deepClone(obj, hash = new WeakMap()) {
// 处理基本数据类型和null
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理循环引用
if (hash.has(obj)) {
return hash.get(obj);
}
// 处理Date和RegExp
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 创建新对象或数组
const cloneObj = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));
// 保存到hash中,用于处理循环引用
hash.set(obj, cloneObj);
// 递归拷贝所有属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], hash);
}
}
// 处理Symbol属性
const symbolKeys = Object.getOwnPropertySymbols(obj);
for (let key of symbolKeys) {
cloneObj[key] = deepClone(obj[key], hash);
}
return cloneObj;
}
3. 使用第三方库
- Lodash 的
_.cloneDeep() - jQuery 的
$.extend(true, {}, obj)
二、节流 (Throttle)
什么是节流?
节流是指在一个连续的操作中,无论操作多么频繁,都按照固定的时间间隔执行函数。比如:滚动事件、鼠标移动事件等高频触发的事件。
实现节流的方法
1. 时间戳版
function throttle(fn, delay) {
let prev = 0;
return function(...args) {
const now = Date.now();
if (now - prev > delay) {
fn.apply(this, args);
prev = now;
}
};
}
2. 定时器版
function throttle(fn, delay) {
let timer = null;
return function(...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
}
};
}
3. 结合版(最常用)
function throttle(fn, delay) {
let timer = null;
let prev = 0;
return function(...args) {
const now = Date.now();
const remaining = delay - (now - prev);
if (remaining <= 0 || remaining > delay) {
if (timer) {
clearTimeout(timer);
timer = null;
}
prev = now;
fn.apply(this, args);
} else if (!timer) {
timer = setTimeout(() => {
prev = Date.now();
timer = null;
fn.apply(this, args);
}, remaining);
}
};
}
使用场景
- 窗口调整(resize)
- 滚动事件(scroll)
- 鼠标移动(mousemove)
- 输入框实时搜索(可以结合防抖)
三、防抖 (Debounce)
什么是防抖?
防抖是指在事件被触发后,等待一段时间再执行函数,如果在这段时间内事件又被触发,则重新计时。适用于连续事件结束后触发一次的场景。
实现防抖的方法
1. 基础版
function debounce(fn, delay) {
let timer = null;
return function(...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
};
}
2. 立即执行版
function debounce(fn, delay, immediate = false) {
let timer = null;
return function(...args) {
if (timer) clearTimeout(timer);
if (immediate) {
const callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, delay);
if (callNow) fn.apply(this, args);
} else {
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
}
};
}
3. 返回值版
function debounce(fn, delay, immediate = false) {
let timer = null;
let result;
return function(...args) {
if (timer) clearTimeout(timer);
if (immediate) {
const callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, delay);
if (callNow) result = fn.apply(this, args);
} else {
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
}
return result;
};
}
使用场景
- 搜索框输入(等待用户停止输入后再发送请求)
- 窗口大小调整完成后的计算
- 表单验证(等待用户停止输入后验证)
- 按钮连续点击(防止重复提交)
四、节流与防抖的区别
| 特性 | 节流 (Throttle) | 防抖 (Debounce) |
|---|---|---|
| 执行时机 | 固定时间间隔执行一次 | 停止触发后一段时间执行 |
| 适用场景 | 高频连续事件,需要均匀响应 | 连续事件结束后触发一次 |
| 比喻 | 水龙头滴水(固定频率) | 电梯关门(最后一个人进入后关门) |
五、实际应用示例
1. 节流示例 - 滚动加载更多
window.addEventListener('scroll', throttle(function() {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100) {
loadMoreData();
}
}, 200));
2. 防抖示例 - 搜索框
const input = document.querySelector('input');
input.addEventListener('input', debounce(function(e) {
fetchResults(e.target.value);
}, 500));
3. 组合使用示例
// 输入时防抖,提交时立即执行
const searchInput = document.querySelector('#search');
const searchButton = document.querySelector('#search-btn');
const debouncedSearch = debounce(performSearch, 500);
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
searchButton.addEventListener('click', () => {
debouncedSearch.cancel(); // 取消防抖计时
performSearch(searchInput.value); // 立即执行
});
function performSearch(query) {
// 执行搜索逻辑
}
// 在防抖函数中添加cancel方法
function debounce(fn, delay) {
let timer = null;
function debounced(...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
}
debounced.cancel = () => {
if (timer) {
clearTimeout(timer);
timer = null;
}
};
return debounced;
}
六、总结
- 深拷贝:用于完全复制复杂对象,需要注意处理各种特殊情况(循环引用、Date、RegExp等)
- 节流:控制函数执行频率,适用于需要均匀响应的高频事件
- 防抖:延迟函数执行,适用于连续事件结束后的操作
在实际开发中,可以根据具体场景选择合适的实现方式,或者使用成熟的工具库如Lodash中的_.cloneDeep()、_.throttle()和_.debounce()方法。
附:前端学习资料大全
百度网盘:链接: https://pan.baidu.com/s/1OTc6cFnjq4Y1vp_itHL_qA?pwd=hxj4 提取码: hxj4
诸君共勉!有问题,可以评论区多多发言~
1062

被折叠的 条评论
为什么被折叠?



