来自 developer.mozilla.org/“深层复制”页面:
属性都具有原始值的对象的副本既符合深复制又符合浅复制的定义。
我不确定我是否理解这句话。
下面是一个片段,我使用
x
值创建一个实体 'hello'
,然后通过 y
将其分配给另一个新变量 y = x
。来自另一种语言,我想知道 y
和 x
是否是独立的,或者改变一个会影响另一个。从执行代码的结果来看,我明白它们是无关的。
x = 'hello';
y = x;
y = 'world';
console.log(x)
console.log(y)
但是,如果
x
是一个对象,例如{ k: 'v' }
,那么看起来 y = x
定义了 y
,它基本上只是 x
的别名:
x = { k: 'v' }
y = x;
y.k = 'w';
console.log(x)
console.log(y)
在后一个片段中,
x
与的描述不匹配
属性都具有原始值的对象
假设它只有一个与字符串值
'v'
关联的属性?
如果是这样的话,那么上述引用对于后者意味着什么
x
?
变量赋值不是复制,是引用。复制是指创建具有相同属性且每个属性具有相同值的新对象。
变量可以是基元或对象。原语是“字符串”、“数字”和“布尔值”,也请保持简短。在 javascript 的对象类别中,几乎所有非原语的东西都属于对象类别,如数组、函数等。
当您将原语分配给变量时,该变量会将内存中的位置保存为该值。当您将源变量的值分配给新变量时,内存中会出现一个具有相同位的新空间,并且新变量保存指向内存中新位置的指针。所以:
var a = "something"; //lets say this is the source var
var b = a; //this will create a copy of a. When you change b, a is not affected
对于任何其他原语也是如此。
对于物体来说,故事完全是另一回事。对象通过引用保存在内存中,当您从另一个变量分配新变量时,它们将指向内存中相同的精确位置。
var a = { foo:"bar" }
var b = a; //this will point to the same exact object. when you change b.foo = "new" then also a.foo will be equal to "new" because is the same object.
这个逻辑也适用于对象内部属性的嵌套。数组将其视为一个特殊的对象,其键是连续的数字,并通过名为 length 的属性来跟踪元素的数量。因此,当您听到数组时,也会想到参考值。
现在考虑以下事项:
var sourceObj = {
prop1 : 123,
prop2 : "something"
prop3 : {
foo: "bar"
},
prop4 : [1,"2",{key:3},[10,20,30]] //this has it all kinds
}
var newObjReference = sourceObj; //this case is clear as it would be identical to access anything from sourceObj.propX same as newObjReference.propX
现在将对象视为该属性的容器,是声明一些变量的地方。 (为了清楚起见,我在这里过于简单化了)。
浅拷贝只会创建一个具有与原始对象(sourceObj)相同的 props 的新容器,但内部的其他所有内容都遵循上面解释的相同 valueType 和 referenceType 规则。
var shallowManualCopy = {
prop1: sourceObj.prop1, //this will be copied as it is a primitive
prop2: sourceObj.prop2, //same with this will be copied
prop3: sourceObj.prop3, //this will reference the same identical object that sourceObj.prop3 has because it is an object. remember the part above
prop4: sourceObj.prop4 //same with the array. it will reference the same identical array not a copy, but THAT array.
}
所以如果我更改shallowManualCopy.prop1,那么sourceObj.prop1将不会受到影响。与 prop2 相同。但另外,如果为shallowManualCopy.prop3分配一个新值,那么sourceObjc.prop3将不会受到影响,因为我们只是更改新对象(新容器)内的prop。
但是:
如果我更改shallowManualCopy.prop3.foo =“new”,那么sourceObj.prop3.foo也将是“新”,因为它们是同一个对象。与数组的任何元素相同。如果我将shallowManualCopy.prop4[2]更改为“somethingElse”,那么sourceObj.prop4[2]将是“somethingElse”
现在深层副本(手动制作以解释)将类似于:
var deepManualCopy = { //a new object container
prop1: sourceObj.prop1, //this will be copied as it is a primitive
prop2: sourceObj.prop2, //same with this will be copied
prop3: { //another new object
foo: sourceObj.prop3.foo, //this is primitive. so will copy
},
prop4: [ //a new array
sourceObj.prop4[0], //primitive
sourceObj.prop4[1], //primitive
{ // another new object
key: sourceObj.prop4[2].key, //primitive
},
[ //another new array
sourceObj.prop4[3][0], //primitive
sourceObj.prop4[3][1], //primitive
sourceObj.prop4[3][2], //primitive
]
]
}
TL;博士;
要在 javascript 中进行深度复制,您必须使用 StructuredClone(sourceObject) 或 JSON.parse(JSON.stringify(sourceObject)) 对于可序列化对象。
可序列化对象是指内部没有循环引用或不可序列化属性(如函数)的对象(过于简单化)
浅拷贝是一个新对象(不是同一个对象),但包含所有属性(如 sourceObject)以及 sourceObject 中的所有值(如果不是基元)作为引用。
我希望你能从这一切中学到一些东西。