自己建购物网站,网站转备案,长安网站建设软件,模板大全免费目录 浅拷贝实现 深拷贝实现自己手写 浅拷贝
浅拷贝是指创建一个新对象#xff0c;这个对象具有原对象属性的精确副本 基本数据类型#xff08;如字符串、数字等#xff09;#xff0c;在浅拷贝过程中它们是通过值传递的#xff0c;而不是引用传递#xff0c;修改值并不… 目录 浅拷贝实现 深拷贝实现自己手写 浅拷贝
浅拷贝是指创建一个新对象这个对象具有原对象属性的精确副本 基本数据类型如字符串、数字等在浅拷贝过程中它们是通过值传递的而不是引用传递修改值并不会影响原对象 如果这些属性是引用类型如对象、数组等浅拷贝只会复制它们的引用而不会复制它们的内容 浅拷贝后的新对象和原对象中的引用类型属性仍然指向相同的内存地址修改其中一个的引用类型数据会影响另一个
实现 Object.assign(target, source)用于将所有可枚举的属性从一个或多个源对象复制到目标对象返回目标对象 const obj {name: obj,age: 18,height: 180,o: {a: 1,b: 2,},
};
const copy Object.assign({ height: 188 }, obj);
console.log(copy); // {height: 180, name: obj, age: 18, o:{...}}
copy.name copy;
console.log(obj.name); // obj
console.log(copy.name); // copy
copy.o.a 11;
console.log(copy.o); // {a: 11, b: 2}
console.log(obj.o); // {a: 11, b: 2}数组的 slice() 方法对于数组slice() 方法可以用来进行浅拷贝。它返回一个新数组并将原数组中的元素逐个复制到新数组中但如果数组的元素是对象它们仍然共享相同的引用 const names [abc, def, { name1: ghi, name2: cba }];
const copy names.slice(1);
console.log(copy); // [def, {name1: ghi, name2: cba}]
copy[1].name1 abc;
console.log(copy[1]); // {name1: abc, name2: cba}
console.log(names[2]); // {name1: abc, name2: cba}扩展运算符spread operator ...适用于数组和对象 const obj {name: obj,age: 18,height: 180,o: {a: 1,b: 2,},
};
const names [abc, def, { name1: ghi, name2: cba }];
const copy1 { ...obj };
const copy2 [ ...names ];
copy1.o.a 11;
console.log(copy1.o); // {a: 11, b: 2}
console.log(obj.o); // {a: 11, b: 2}copy2[1].name1 abc;
console.log(copy2[2]); // {name1: abc, name2: cba}
console.log(names[2]); // {name1: abc, name2: cba}实现的图解 浅拷贝对基本数据类型有效但对于对象、数组等引用类型只是复制了它们的引用这会导致在修改拷贝时原对象也被修改。如果需要对嵌套对象和数组进行完全独立的拷贝则需要使用深拷贝
深拷贝
深拷贝是指将一个对象的所有属性都完整地复制到另一个对象中包括嵌套的对象或数组。深拷贝与浅拷贝不同浅拷贝只复制对象的引用而深拷贝会递归地复制对象的所有层次确保原始对象和新对象完全独立任何一方的修改不会影响另一方
实现 JSON实现这是最简单的一种方式适合处理不包含函数、undefined、Symbol、循环引用等特殊类型的对象序列化有问题的情况如下 undefined 不会被序列化且在对象属性值中会被删除在数组中则会被转化为 null Symbol 是唯一的标识符无法被序列化且会被丢弃 Date 对象会被序列化为字符串但当反序列化时它不再是 Date 对象而是一个普通字符串 如果对象有循环引用JSON.stringify 会抛出错误因为它无法处理递归结构 Map 和 Set 结构会被序列化为空对象并且在反序列化时无法恢复为原始结构 不会序列化对象的原型链属性因此对象的继承关系会丢失 const set new Set();
const obj {name: obj,age: 18,height: undefined,o: {a: 1,b: 2,},[Symbol()]: symbol,[set]: set,date: new Date()
};
console.log(JSON.parse(JSON.stringify(obj))); // {name: obj, age: 18, o: {…}, [object Set]: {}, date: 2024-09-14T06:48:44.497Z}使用 structuredClone()在一些现代浏览器中可以使用内置的 structuredClone() 来实现深拷贝。它可以处理大多数情况下的深拷贝需求包括循环引用、Date、Map 和 Set 等 不能拷贝 Symbol属性Symbol 类型属性会被忽略因为 Symbol 是唯一的标识符具有不可枚举性和唯一性 拷贝 Symbol 值会报错Failed to execute structuredClone on Window: Symbol() could not be cloned 不会拷贝对象的原型链属性 const obj {name: Alice,age: undefined,[Symbol()]: symbol, // 会忽略
};const clone structuredClone(obj);
console.log(clone); // { name: Alice, age: undefined }使用 Lodash 库中的 _.cloneDeep()Lodash 是一个非常流行的 JavaScript 工具库其中提供了 _.cloneDeep() 方法可以轻松实现深拷贝对于大部分普通对象、数组、Set 和 Map能够正确处理并进行深拷贝 无法深拷贝 Symbol 属性但可以克隆对象中以 Symbol 作为值的属性 const sym Symbol(id);
const obj {[sym]: value,id: Symbol(id),name: Alice
};
const clone _.cloneDeep(obj);
console.log(clone); // { id: Symbol(id), name: Alice } -- Symbol 属性被忽略Symbol 值被正确克隆自己手写
实现对对象和基本数据类型的拷贝对 Symbol 的 key 进行处理其他数据类型的值进程处理数组、函数、Symbol、Set、Map对循环引用的处理
function deepCopy(originValue, map new WeakMap()) {// 0.如果值是Symbol的类型if (typeof originValue symbol) {return Symbol(originValue.description)}// 1.如果是原始类型, 直接返回if (!isObject(originValue)) {return originValue}// 2.如果是set类型if (originValue instanceof Set) {const newSet new Set()for (const setItem of originValue) {newSet.add(deepCopy(setItem))}return newSet}// 3.如果是函数function类型, 不需要进行深拷贝if (typeof originValue function) {return originValue}// 4.如果是对象类型, 才需要创建对象if (map.get(originValue)) {return map.get(originValue)}const newObj Array.isArray(originValue) ? []: {}map.set(originValue, newObj)// 遍历普通的keyfor (const key in originValue) {newObj[key] deepCopy(originValue[key], map);}// 单独遍历symbolconst symbolKeys Object.getOwnPropertySymbols(originValue)for (const symbolKey of symbolKeys) {newObj[Symbol(symbolKey.description)] deepCopy(originValue[symbolKey], map)}return newObj
}