浅拷贝:
function shallowClone(obj) {
let cloneObj = {};
for (let key in obj) {
cloneObj[key] = obj[key];
}
return cloneObj;
}
深拷贝:
基础版(未考虑循环引用)
function deepClone(target) {
if (!target || typeof target !== "object") {
return target;
}
let result = Array.isArray(target) ? [] : {};
for (let key in target) {
result[key] = deepClone(target[key]);
}
return result;
}
注:如果为了性能考虑,可以将for... in 循环改为while 循环。
使用Map解决循环引用问题
Map类型可以使用object作为key值。使用Map类型保存每次克隆的对象,这样就不会出现子元素->父对象->子元素....的循环
function deepClone(target, map = new Map()) {
if (!target || typeof target !== "object") {
return target;
}
if (map.get(target)) {
return map.get(target);
}
let result = Array.isArray(target) ? [] : {};
map.set(target, result);
for (let key in target) {
result[key] = deepClone(target[key], map);
}
return result;
}
附 while 循环和 for... in 循环性能对比:
const whileLoop = (array) => {
const start = Date.now();
const length = array.length;
let i = 0;
let sum;
while (i < length) {
sum += array[i];
i++;
}
console.info(Date.now() - start);
};
const forInLoop = (array) => {
const start = Date.now();
let sum;
for (let key in array) {
sum += array[key];
}
console.info(Date.now() - start);
};
const forLoop = (array) => {
const start = Date.now();
const length = array.length;
let sum;
for (let i = 0; i < length; i++) {
sum += array[i];
}
console.info(Date.now() - start);
};
let testArray = Array.from({ length: 500000 }, (item, index) => index + 1);
whileLoop(testArray);
forInLoop(testArray);
forLoop(testArray);
防抖
目的:降低同一事件触发的频率,减少浏览器性能消耗
效果:短时间内多次触发同一事件,事件处理函数只会在停止触发事件后执行一次
function debounce(fn, delay) {
let timer;
return function () {
let _this = this;
let args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
fn.apply(_this, args);
}, delay);
};
}
节流
结果:短时间内多次触发同一事件,事件处理函数只会每隔一段时间执行一次
function throttle(fn, delay) {
let timer;
return function () {
let _this = this;
let args = arguments;
if (timer) {
return;
}
timer = setTimeout(function () {
fn.apply(_this, args);
timer = null;
}, delay);
};
}
call、apply、bind
call
思路主要是在要绑定this的对象上新建匿名属性,然后直接调用。
Function.prototype.myCall = function (obj, ...args) {
const func = this;
const tempFunc = Symbol("temp");
obj[tempFunc] = func;
const result = obj[tempFunc](...args);
delete obj[tempFunc];
return result;
};
apply和call仅args不同,不再重复
bind
Function.prototype.myBind = function (obj, ...args) {
const func = this;
const fbound = function (...otherArgs) {
return func.call(new.target ? this : obj, ...args, ...otherArgs);
};
fbound.prototype = Object.create(func.prototype);
fbound.prototype.constructor = fbound;
return fbound;
};