深拷贝
在 JavaScript 中,深拷贝是指创建一个新的对象,并将原始对象的所有属性和嵌套对象的属性都复制到新对象中,确保原始对象和新对象之间没有引用关系。这样做可以避免在修改新对象时影响到原始对象。
以下是几种常见的 JavaScript 深拷贝方法:
手动递归复制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function deepCopy(obj) { if (typeof obj !== "object" || obj === null) { return obj; }
let copy = Array.isArray(obj) ? [] : {};
for (let key in obj) { if (obj.hasOwnProperty(key)) { copy[key] = deepCopy(obj[key]); } }
return copy; }
|
使用 JSON 序列化和反序列化:
1
| let copy = JSON.parse(JSON.stringify(obj));
|
这种方法可以将对象转换为字符串,然后再将字符串转换回对象,从而实现深拷贝。但是需要注意的是,它无法复制函数和特殊对象(如正则表达式、Date 对象等),并且会忽略对象的原型链。
使用第三方库(如 Lodash):
第三方库 Lodash 提供了 cloneDeep 方法,可以方便地进行深拷贝:
1 2
| const _ = require("lodash"); let copy = _.cloneDeep(obj);
|
这种方法可以处理各种类型的对象,并且具有良好的性能和兼容性。
需要注意的是,深拷贝可能会导致循环引用的问题,即某个对象的属性引用了自身或者形成了循环引用链。在进行深拷贝时,需要确保处理循环引用的情况,否则可能会导致无限递归的问题。
选择合适的深拷贝方法取决于你的具体需求和使用场景。如果你只需要简单的数据结构拷贝,手动递归复制或使用 JSON 序列化和反序列化可能已经足够。如果需要处理复杂的对象和循环引用,可以考虑使用第三方库来进行深拷贝。
防抖
防抖(debouncing)是一种常用的前端技术,用于限制某个函数在短时间内被频繁触发的情况。当一个事件被触发时,防抖会延迟执行该事件的处理函数,如果在延迟期间内该事件再次被触发,那么延迟时间会被重新计算。这样可以有效地减少函数的执行次数,提升性能。
下面是一个简单的 JavaScript 示例代码,演示了如何实现防抖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| function debounce(func, delay) { let timerId;
return function () { const context = this; const args = arguments;
clearTimeout(timerId); timerId = setTimeout(function () { func.apply(context, args); }, delay); }; }
function handleInput() { console.log("处理输入..."); }
const debouncedHandleInput = debounce(handleInput, 300);
document .getElementById("input") .addEventListener("input", debouncedHandleInput);
|
在上面的示例中,debounce 函数接受两个参数:func 是要执行的函数,delay 是延迟的时间间隔(以毫秒为单位)。它返回一个新的函数,这个函数会在延迟期间内被多次调用时,只执行最后一次调用。
你可以根据自己的需求调整延迟时间,以及要执行的函数。在示例中,我们将 handleInput 函数包装在 debounce 中,并将返回的函数 debouncedHandleInput 用作输入事件的处理函数。这样,当用户输入时,handleInput 函数不会立即执行,而是在用户停止输入一段时间后才会执行。
节流
节流(throttling)是另一种常用的前端技术,用于限制某个函数在一定时间间隔内被触发的频率。与防抖不同,节流会在固定的时间间隔内执行函数,而不管该函数是否被频繁触发。
下面是一个简单的 JavaScript 示例代码,演示了如何实现节流:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function throttle(func, delay) { let timerId; let lastExecutedTime = 0;
return function () { const context = this; const args = arguments; const currentTime = Date.now();
if (currentTime - lastExecutedTime >= delay) { func.apply(context, args); lastExecutedTime = currentTime; } else { clearTimeout(timerId); timerId = setTimeout(function () { func.apply(context, args); lastExecutedTime = Date.now(); }, delay); } }; }
function handleScroll() { console.log("处理滚动..."); }
const throttledHandleScroll = throttle(handleScroll, 300);
window.addEventListener("scroll", throttledHandleScroll);
|
在上面的示例中,throttle 函数接受两个参数:func 是要执行的函数,delay 是时间间隔(以毫秒为单位)。它返回一个新的函数,这个函数会在固定的时间间隔内被调用,无论被调用的次数。
在示例中,我们将 handleScroll 函数包装在 throttle 中,并将返回的函数 throttledHandleScroll 用作滚动事件的处理函数。这样,无论用户多快地滚动页面,handleScroll 函数都会以固定的时间间隔被执行。
你可以根据自己的需求调整时间间隔,以及要执行的函数。请注意,节流会在固定的时间间隔内执行函数,而不会像防抖那样等待用户停止触发事件。
转置矩阵
要转置一个矩阵,可以将矩阵的行变为列,列变为行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| function transposeMatrix(matrix) { const rows = matrix.length; const cols = matrix[0].length; const transposedMatrix = []; for (let i = 0; i < cols; i++) { transposedMatrix[i] = []; for (let j = 0; j < rows; j++) { transposedMatrix[i][j] = matrix[j][i]; } } return transposedMatrix; }
const matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ];
const transposed = transposeMatrix(matrix); console.log(transposed); [ [1, 4, 7], [2, 5, 8], [3, 6, 9], ];
|
矩阵列匹配
有问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| let arr = [ [1, 2], ["a", "b"], ]; let list = []; let r_list = [];
const fn = ($arr, $i) => { for (let i = 0; i < $arr[$i].length; i++) { r_list[$i] = $arr[$i][i]; if ($i !== $arr.length - 1) { fn($arr, $i + 1); } else { list.push(r_list.slice()); } } };
fn(arr, 0); console.log(list);
|
矩阵列生成所有组合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| function matrixColumnMatch(matrix) { let results = [];
function backtrack(currentCombination, depth) { if (depth === matrix.length) { results.push([...currentCombination]); return; } for (let i = 0; i < matrix[depth].length; i++) { currentCombination.push(matrix[depth][i]); backtrack(currentCombination, depth + 1); currentCombination.pop(); } }
backtrack([], 0); return results; }
const matrix = [ [1, 2], ["a", "b"], ["X", "Y"], ];
const combinations = matrixColumnMatch(matrix); console.log(combinations);
|