对象复制:分类讨论
1.可以用lodash
2.不能用库,可以用浏览器自带api,structuredClone
const obj1 = { a: 0, b: { c: 0 } };
const obj2 = Object.assign({}, obj1);
console.log(obj2); // { a: 0, b: { c: 0 } }
obj1.a = 1;
console.log(obj1); // { a: 1, b: { c: 0 } }
console.log(obj2); // { a: 0, b: { c: 0 } }
obj2.a = 2;
console.log(obj1); // { a: 1, b: { c: 0 } }
console.log(obj2); // { a: 2, b: { c: 0 } }
obj2.b.c = 3;
console.log(obj1); // { a: 1, b: { c: 3 } }
console.log(obj2); // { a: 2, b: { c: 3 } }
// Deep Clone
const obj3 = { a: 0, b: { c: 0 } };
const obj4 = structuredClone(obj3);
obj3.a = 4;
obj3.b.c = 4;
console.log(obj4); // { a: 0, b: { c: 0 } }
3.lodash深拷贝源码
浅拷贝:将B对象拷贝到A对象中,但不包括B里面的子对象
深拷贝:将B对象拷贝到A对象中,包括B里面的子对象
shallow copy vs deep cloneA shallow copy of an object is a copy whose properties share the same references (point to the same underlying values) as those of the source object from which the copy was made. As a result, when you change either the source or the copy, you may also cause the other object to change too. That behavior contrasts with the behavior of a deep copy, in which the source and copy are completely independent.
More formally, two objects o1 and o2 are shallow copies if:
-They are not the same object (o1 !== o2).
-The properties of o1 and o2 have the same names in the same order.
-The values of their properties are equal.
-Their prototype chains are equal.
For shallow copies, only the top-level properties are copied, not the values of nested objects. Therefore:
-Re-assigning top-level properties of the copy does not affect the source object.
-Re-assigning nested object properties of the copy does affect the source object.
1. alteredTarget = Object.assign(tartget, source1,source2)
If the source value is a reference to an object, it only copies the reference value.
let obj1={a:0,b:{c:0}};
let obj2=Object.assign({},obj1);
console.log(JSON.stringify(obj2));// { "a": 0, "b": { "c": 0}}
obj1.a=1;
obj2.a=2;
obj2.b.c=3;
console.log(JSON.stringify(obj1));// { "a": 1, "b": { "c": 3}}
console.log(JSON.stringify(obj2));// { "a": 2, "b": { "c": 3}}
copies all enumerable own properties from one or more source objects to a target object. It returns the target object. Properties on the prototype chain and non-enumerable properties cannot be copied
Properties in the target object are overwritten by properties in the sources if they have the same key. Later sources' properties overwrite earlier ones.
The Object.assign() method only copies enumerable and own properties from a source object to a target object. It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters. Therefore it assigns properties, versus copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters.
2. ...spread operator
In JavaScript, all standard built-in object-copy operations (spread syntax, Array.prototype.concat(), Array.prototype.slice(), Array.from(), Object.assign(), and Object.create()) create shallow copies rather than deep copies.
A deep copy of an object is a copy whose properties do not share the same references (point to the same underlying values) as those of the source object from which the copy was made. As a result, when you change either the source or the copy, you can be assured you're not causing the other object to change too. That behavior contrasts with the behavior of a shallow copy, in which changes to nested properties in the source or the copy may cause the other object to change too.
Two objects o1 and o2 are structurally equivalent if their observed behaviors are the same. These behaviors include:
-The properties of o1 and o2 have the same names in the same order.
-The values of their properties are structurally equivalent.
-Their prototype chains are structurally equivalent (although when we deal with structural equivalence, these objects are usually plain objects, meaning they both inherit from Object.prototype).
Structurally equivalent objects can either be the same object (o1 === o2) or copies (o1 !== o2). Because equivalent primitive values always compare equal, you cannot make copies of them.
We can now define deep copies more formally as:
-They are not the same object (o1 !== o2).
-The properties of o1 and o2 have the same names in the same order.
-The values of their properties are deep copies of each other.
-Their prototype chains are structurally equivalent.
Deep copies may or may not have their prototype chains copied (and often they do not). But two objects with structurally non-equivalent prototype chains (for example, one is an array and the other is a plain object) are never copies of each other.
One way to make a deep copy of a JavaScript object, if it can be serialized, is to use JSON.stringify() to convert the object to a JSON string, and then JSON.parse() to convert the string back into a (completely new) JavaScript object:
1. clone = JOSN.parse(JSON.stringify(obj))
const ingredientsList = ["noodles", { list: ["eggs", "flour", "water"] }];
const ingredientsListDeepCopy = JSON.parse(JSON.stringify(ingredientsList));
Because a deep copy shares no references with its source object, any changes made to the deep copy do not affect the source object.
// Change the value of the 'list' property in ingredientsListDeepCopy.
ingredientsListDeepCopy[1].list = ["rice flour", "water"];
// The 'list' property does not change in ingredients_list.
console.log(ingredientsList[1].list);
// Array(3) [ "eggs", "flour", "water" ]
序列化的时候遇到undefined和函数会跳过
2.web API structuredClone()
The web API structuredClone() also creates deep copies and has the advantage of allowing transferable objects in the source to be transferred to the new copy, rather than just cloned. It also handles more data types, such as Error. But note that structuredClone() isn't a feature of the JavaScript language itself — instead it's a feature of browsers and other JavaScript hosts that implement web APIs. And calling structuredClone() to clone a non-serializable object will fail in the same way that calling JSON.stringify() to serialize it will fail.
写一个深拷贝,只考虑基本数据类型和Object
对需要拷贝的对象的属性进行递归遍历,如果对象的属性不是基本类型时,就继续递归;遍历到对象属性为基本类型,将属性和属性值赋给新对象。
function deepClone(obj) {
if(typeof obj !== 'object' || obj === null) return obj; //base
let clone = Array.isArray(obj) ? [] : {};
Object.keys(obj).forEach(key=> {
clone[key]= typeof obj[key] === 'object' ? deepClone(obj[key]):obj[key]
})
return clone;
}
如何解决对象环绕的问题,例如a.b.a对象a的属性b指向的是a本身,这种情况如何实现深拷贝?
类型考虑全面
Number/String/Boolean/null/undefined
Object
Array、{}、Date
循环依赖(利用ES6的Map)
function是否可以深拷贝
闭包(因为function是有上下文的)
实现深度拷贝函数,并支持自定义拷贝
// target 为任意类型的值。
// customize 是一个函数,接受参数为深度拷贝过程中的属性(prop)、值(value),函数返回任意值作为当前属性的拷贝。
function deepCopy(target, customize) {
// your code
}
https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript
网友评论