使用 JSON.stringify 和 JSON.parse
当我们复制一个对象及其所引用的对象时,就会发生深度复制。
我们可以通过混合使用 JSON.stringify 和 JSON.parse 来创建深层副本。
首先,我们应该 JSON.stringify() 解析它的 json 对象以取回对象。
JSON.parse() 方法旨在解析和构造由字符串描述的 JavaScript 对象或者值。
对象的新字段有它们的内存地址并且独立于嵌套的对象字段。
下面是一个深度克隆的例子:
//Deep Clone obj = { a: 0, b: { c: 0 } }; let cloneObj = JSON.parse(JSON.stringify(obj)); obj.a = 2; obj.b.c = 2; console.log(JSON.stringify(obj)); //{ a: 2, b: { c: 2}} console.log(JSON.stringify(cloneObj)); //{ a: 0, b: { c: 0}} cloneObj.a = 4; cloneObj.b.c = 4; console.log(JSON.stringify(obj)); //{ a: 2, b: { c: 2}} console.log(JSON.stringify(cloneObj)); //{ a: 4, b: { c: 4}}
在 JavaScript 中克隆对象是任何项目的常见任务:从简单的对象到复杂的对象。
通常,赋值运算符不会生成对象的副本。
它能够为它分配一个引用。
让我们看看下面的代码:
let object = { a: 2, b: 3, }; let copy = object; object.a = 5; console.log(copy.a); //Result //a = 5;
对象变量是新初始化对象的容器。
copy变量指向同一个对象,是对象的引用。
对象 { a: 2, b: 3, } 表明存在两种获得成功的方法。
这种方法可以消除任何形式的不变性,从而导致错误。
复制对象有一种简单的方法:它循环遍历原始对象,一个接一个地复制每个属性。
代码如下所示:
function copy(mainObject) { let objectCopy = {}; //objectCopy 将存储 mainObject 的副本 let key; for (key in mainObject) { objectCopy[key] = mainObject[key]; //将每个属性复制到 objectCopy 对象 } return objectCopy; } const mainObject = { a: 1, b: 3, c: { x: 5, y: 4, }, } console.log(copy(mainObject));
但请注意,可能存在固有问题,例如:
- objectCopy 获得了一个新的 Object.prototype 方法,它不同于 mainObject 对象原型方法。但如果我们想要原始对象的副本,这不是我们想要的。
- 无法复制属性描述符。 “可写”描述符(包括设置为 false 的值)将在 objectCopy 对象中为 true。
- 上面显示的代码复制了 mainObject 的可枚举属性。
- 如果原始对象内的属性是对象,则可以在副本和原始对象之间共享。
请注意,JavaScript 对象本质上是可变的,并且存储为引用。
因此,当将对象分配给另一个变量时,我们将对象的内存地址分配给该变量。
在这种情况下,旧对象和新对象指向相同的内存地址。
其中一个的每一个变化都会反映在另一个中。
因此,将一个对象分配给另一个对象不会复制对象。
描述 JavaScript 对象
JavaScript 对象的目的是存储各种数据和更复杂实体的键控集合。
JavaScript 对象包含在所有语言方面;因此,一旦开始学习,就必须学习它们。
我们可以使用图形括号 {...} 轻松创建对象,并且需要具有属性列表。
属性被称为“键:值”,其中键或者属性名称是一个字符串,值可以是任何值。
带有 Spread.Syntax 或者 Object.assign 的浅拷贝
展开语法是复制和/或者合并对象的最短和最简单的方法之一。
该示例将如下所示:
let obj = { key1: "value1", key2: "value2" }; let clonedObject = { ...obj }; console.log(clonedObject); //Object { key1: "value1", key2: "value2" }
Object.assign() 方法用于将所有可枚举属性从一个或者多个源对象复制到返回它的目标对象。
下面是一个例子:
let obj = { key1: "value1", key2: "value2" }; let clonedObject = Object.assign({}, obj); console.log(clonedObject); //Object { key1: "value1", key2: "value2" }
因此,spread 语法和 object.assign 是复制对象的标准方法。
它们是等价的。
上述方法的问题在于它们实现了浅拷贝。
因此,生成了一个新对象,它获得了原始对象值的精确副本。
但是请注意,如果任何对象字段是对其他对象的引用,则只需复制引用地址:仅复制内存地址。
示例如下:
let obj = { a: 0, b: { c: 0 } }; let copySpread = { ...obj }; let copyOA = Object.assign({}, obj); console.log(JSON.stringify(obj)); //{ a: 0, b: { c: 0}} obj.a = 1; console.log(JSON.stringify(obj)); //{ a: 1, b: { c: 0}} console.log(JSON.stringify(copySpread)); //{ a: 0, b: { c: 0}} console.log(JSON.stringify(copyOA)); //{ a: 0, b: { c: 0}} copySpread.a = 2; copyOA.a = 3 console.log(JSON.stringify(obj)); //{ a: 1, b: { c: 0}} console.log(JSON.stringify(copySpread)); //{ a: 2, b: { c: 0}} console.log(JSON.stringify(copyOA)); //{ a: 3, b: { c: 0}} obj.b.c = 4; console.log(JSON.stringify(obj)); //{ a: 1, b: { c: 4}} console.log(JSON.stringify(copySpread)); //{ a: 2, b: { c: 4}} console.log(JSON.stringify(copyOA)); //{ a: 3, b: { c: 4}}
这些方法很方便,但是当我们要复制的对象中有嵌套对象时,不建议我们使用它们。