javaScript记录浅拷贝与深拷贝

在js中,一切皆对象(null和undefined有待另外的理解),JavaScript 中的几乎所有对象都是位于原型链顶部 Object 的实例。

对象的基本的一些操纵,我们是必须要知道的。

let obj = {
  a: 1,
  b: 2,
};
let copy = obj;
copy.a = 5;
console.log(obj.a); // ==> 5

上面的代码应该都能理解,赋值运算符不会创建一个对象的副本,它只分配一个引用,

那我们就想到了,循环遍历对象

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
function shallowCopy(src) {
  var dst = {};
  for (var prop in src) {
    if (src.hasOwnProperty(prop)) {
      dst[prop] = src[prop];
    }
  }
  return dst;
}
shallowObj.a = 4  ==>  obj.a =1
shallowObj.arr[1] = 5 ==> obj.arr[1] = 5

显然上面的遍历是起了一定的效果的,但是这只能算对象的浅拷贝(shallow copy),原因:因为浅拷贝只会将对象的各个属性进行依次复制,并不会进行递归复制,而 JavaScript 存储对象都是存地址的,所以浅拷贝会导致 obj.arr 和 shallowObj.arr 指向同一块内存地址。

那改变一下上面的代码,我们需要用迭代来实现对对象的深拷贝(deep copy)

var obj = { a:1, arr: [2,3] };
var deepObj = deepCopy(obj);
function deepCopy(obj) {
	var newObj = obj.constructor === Array ? [] : {}
	if (typeof obj !== 'object') {
		return
	} else {
		for (var i in obj) {
			if (obj.hasOwnProperty(i)) {
                // 判断子元素是否为对象
				newObj[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i]
			}
		}
	}
	return newObj
}
deepObj.arr[1] = 5
console.log(obj.arr[1])  ==> 3

解释:知乎网友的解释

对于字符串类型,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没 有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变,而深复制则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

项目中,我也遇到Object.assign({},obj) 这种浅拷贝与JSON.parse(JSON.stringfy(obj))这种深拷贝,但是JSON.parse(JSON.stringfy(obj)) 这种方法是有缺陷的,其并不能复制,对象中的方法,但是Object.assign({},obj)可以。

let obj = {
  name: 'demo',
  test: function test() {
    return true;
  },
}
 
let method1 = Object.assign({}, obj);
let method2 = JSON.parse(JSON.stringify(obj));
 
console.log(method1);
/* result
{
  test: function test() {
    return true;
  },
  name: "demo"
}
*/
 
console.log(method2);
/* result
{
  name: "demo"
}
*/

最后,我也看到了一篇文章,《深入剖析 JavaScript 的深复制》,涉及到 jQuery, underscore, lodash 等库关于深复制的实现,有兴趣可以看看。

猜你喜欢

转载自blog.csdn.net/shentibeitaokong/article/details/81166114