复本机能是程式设计中的两个常用操作方式,主要就分成深复本和浅复本,但也是时常难犯错误的两个习题,那时来聊聊Javascript中的复本机能。
在JS中,常用的数组复本操作方式是这种的: str1 = 123; str2 = str1;console.log(str1); str2 = 456; console.log(str1); console.log(str2);比较简单,输入结论如下表所示:
123 123 456下面上看几段浅复本的范例:
obj1 = {a: 1}; obj2 = obj1; console.log(obj2.a); obj2.a = 2; console.log(obj2.a);console.log(obj1.a);输入结论:
1 2 2下面的标识符能看见,当他们把obj1表达式给obj2的后,发生改变了obj2中特性a的值,辨认出obj1中的a反之亦然被发生改变了,即使当把obj1表达式给obj2后,obj1和obj2对准了同一门牌号,这时obj2和obj1是共享资源同一物理门牌号的,能参照下面的此种图:
因此发生改变obj2中的a,相等于发生改变了obj1中的a,这就是浅复本;
接着上看下深复本如何实现:
obj1 = {a: 1, b: {c: 2}}; obj2 = JSON.parse(JSON.stringify(obj1)); obj2.b.c = 3; console.log(obj1.b.c);输入结论:
2能看见通过把对象进行1次序列化+反序列化,把obj1表达式给obj2,然后修改obj2对象中的特性值,最后辨认出obj1中的特性值并没有发生改变,即使obj1和obj2独享自己的一份物理门牌号,这就实现了深复本操作方式,能参照下面的这张图:
但是,下面的深复本方式其实是有问题的,不推荐此种写法,即使此种写法不能覆盖所有的深复本情况,上看几个反例:反例1: 当要复本的对象中包含undefined的特性
obj1 = { a: 1, b: { c: 2, d: undefined } } obj2 = JSON.parse(JSON.stringify(obj1)) console.log(obj2)输入结论:
{ “a”: 1, “b”: { “c”: 2 } }从输入结论会辨认出复本后的obj2对象缺失了特性d。
反例2: 当要复本的对象中包含function特性
obj1 = { a: 1, b: { c: 2, d: function name(params) { console.log(params); } } } obj2 = JSON.parse(JSON.stringify(obj1))console.log(obj2)输入结论:
{ “a”: 1, “b”: { “c”: 2 } }从输入结论会辨认出复本后的obj2对象缺失了特性d。
反例3: 当要复本的对象中包含对象特性obj1 = {a: 1, b: { c: 2, d: new RegExp(\\w+) } } obj2 = JSON.parse(JSON.stringify(obj1)) console.log(obj2)输入结论:
{ “a”: 1, “b”: { “c”: 2, “d”: {} } }从输入结论会辨认出复本后的obj2对象缺失了特性d。
从下面的 3个反例中能看见JSON.parse(JSON.stringify())此种方式并不适合用来做深复本。
下面来介绍在Javascript中深复本的正确姿势: const _ = require(lodash); constexternalObject = {animal: Gator }; const originalObject = { a: 1, b: string, c: false, d: externalObject }; constdeepClonedObject = _.clonedeep(originalObject); externalObject.animal =Lizard; console.log(originalObject);console.log(deepClonedObject);输入结论:
{ a: 1, b: string, c: false, d: { animal: Lizard } } { a: 1, b: string, c: false, d: { animal: Crocodile } }从输入结论能看见,用lodash这个三方库中的clonedeep
方法做到了对象的深度复本,复本后的对象和原对象做到了完全的隔离,如果要完成深复本的功能,推荐使用此种方式。
以上主要就介绍了Javascript中深复本和浅复本的常用用法和误区。