一暮顺、序列化實(shí)現(xiàn)深拷貝的缺點(diǎn)、手寫深拷貝
1羽氮、借助序列化實(shí)現(xiàn)深拷貝惫恼,有哪些缺點(diǎn)?
- ①不能拷貝函數(shù)
- ②不能拷貝Symbol()
- ③不能拷貝循環(huán)引用的對(duì)象(會(huì)報(bào)錯(cuò)祈纯,比如window.window.window.window)
- ④key的值為 undefined不會(huì)拷貝(但是感覺(jué)問(wèn)題不大)
const _ = require("lodash");
const { cloneDeep } = require("./copy");
let s1 = Symbol("aaa");
let s2 = Symbol("bbb");
const obj = {
name: "why",
age: 18,
friend: {
name: "kobe",
friend: {
name: "james",
},
},
hobbies: ["run", "swing"],
food: null,
country: undefined,
[s1]: "aaa",
[s2]: s2,
run: function () {
console.log(this.name, "在跑步");
},
};
// obj.obj = obj;
const copyObj = JSON.parse(JSON.stringify(obj));
// const copyObj = _.cloneDeep(obj);
// const copyObj = cloneDeep(obj);
// 測(cè)試代碼
copyObj.name = "copy" + obj.name;
copyObj.friend.name = "copy" + copyObj.friend.name;
copyObj.hobbies.push("eat");
console.log("====================obj======================");
console.log(obj);
console.log("====================copyObj======================");
console.log(copyObj);
// obj.run();
// copyObj.run();
// console.log(obj[s2] === copyObj[s2]);
====================obj======================
{
name: 'why',
age: 18,
friend: { name: 'kobe', friend: { name: 'james' } },
hobbies: [ 'run', 'swing' ],
food: null,
country: undefined,
run: [Function: run],
[Symbol(aaa)]: 'aaa',
[Symbol(bbb)]: Symbol(bbb)
}
====================copyObj======================
{
name: 'copywhy',
age: 18,
friend: { name: 'copykobe', friend: { name: 'james' } },
hobbies: [ 'run', 'swing', 'eat' ],
food: null
}
2粒没、實(shí)現(xiàn)對(duì)象的深拷貝要注意哪些問(wèn)題簇爆?
- ①對(duì)象類型需要遞歸拷貝
- ②數(shù)組和對(duì)象類型需要做區(qū)分
- ③函數(shù)本就是為了實(shí)現(xiàn)代碼復(fù)用,所以函數(shù)不需要拷貝响蓉,直接再次引用即可
- ④對(duì)于symbol類型哨毁,使用
for in
語(yǔ)法無(wú)法獲取,可以使用 Object.getOwnPropertySymbols(obj)
語(yǔ)法
- ⑤對(duì)于
obj.obj.obj === obj
這種循環(huán)引用,可以使用WeakMap存一份软能,然后有值直接進(jìn)行引用賦值即可。避免死循環(huán)
// copy.js
function cloneDeep(obj) {
let map = new WeakMap();
return _cloneDeep(obj, map);
}
function _cloneDeep(obj, map) {
if (
typeof obj !== "object" ||
obj === null ||
typeof obj === "function" ||
typeof obj === "symbol"
) {
return obj;
}
if (map.has(obj)) return map.get(obj);
let copyObj = null;
if (Array.isArray(obj)) {
copyObj = [];
} else {
copyObj = {};
}
map.set(obj, copyObj);
for (const key in obj) {
copyObj[key] = _cloneDeep(obj[key], map);
}
for (const key of Object.getOwnPropertySymbols(obj)) {
copyObj[key] = _cloneDeep(obj[key], map);
}
return copyObj;
}
module.exports = {
cloneDeep,
};
3、手寫事件總線跋核,實(shí)現(xiàn) emmit、on蹋订、off
三個(gè)方法
class EventBus {
constructor() {
this.evnentStore = {};
}
on(eventName, callback) {
let list = this.evnentStore[eventName];
if (!list) {
list = [];
this.evnentStore[eventName] = list;
}
if (list.indexOf(callback) < 0) list.push(callback);
}
off(eventName, callback) {
let list = this.evnentStore[eventName];
if (!list) return;
let index = list.indexOf(callback);
if (index >= 0) list.splice(index, 1);
}
emmit(eventName) {
let list = this.evnentStore[eventName];
if (!list) return;
for (const item of list) {
item();
}
}
}
const eventBus = new EventBus();
// 監(jiān)聽(tīng)一
const func1 = function () {
console.log("function1 listen to aaa");
};
eventBus.on("aaa", func1);
// 監(jiān)聽(tīng)二
const func2 = function () {
console.log("function2 listen to aaa");
};
eventBus.on("aaa", func2);
// 監(jiān)聽(tīng)三
const func3 = function () {
console.log("function3 listen to bbb");
};
eventBus.on("bbb", func3);
// 觸發(fā)事件
eventBus.emmit("aaa");
// 移除事件
eventBus.off("aaa", func2);
// 觸發(fā)事件
eventBus.emmit("aaa");