理解JavaScript深浅拷贝以及方法

先考虑一种情况,对一个已知对象进行拷贝,编译系统会自动调用一种构造函数——拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数****。

执行结果:调用一次构造函数,调用两次析构函数,两个对象的指针成员所指内存相同,name指针被分配一次内存,但是程序结束时该内存却被释放了两次,会造成内存泄漏问题!

这是由于编译系统在我们没有自己定义拷贝构造函数时,会在拷贝对象时调用默认拷贝构造函数,进行的是浅拷贝!即对指针name拷贝后会出现两个指针指向同一个内存空间。

所以,在对含有指针成员的对象进行拷贝时,必须要自己定义拷贝构造函数,使拷贝后的对象指针成员有自己的内存空间,即进行深拷贝,这样就避免了内存泄漏发生。

执行结果:调用一次构造函数,一次自定义拷贝构造函数,两次析构函数。两个对象的指针成员所指内存不同。

总结:浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

深拷贝方法:

  1. 使用JSON.parse()JSON.stringify()对对象进行拷贝

    通常情况下,我们可以使用JSON.parse()JSON.stringify()实现对象的深克隆,如下:

    var clone = function (obj) {
    	return JSON.parse(JSON.stringify(obj));
    }
    // 这种方法只适用于纯数据json对象的深度克隆,因为有些时候,这种方法也有缺陷
    
  2. 目前没有发现bug的对象深拷贝方法

    var clone = function (obj) {
    	if (obj === null) return null
    
    	if (typeof obj !== 'object') return obj
    
    	if (obj.constructor === Date) return new Date(obj)
    
    	if (obj.constructor === RegExp) return new RegExp(obj)
    
    	var newObj = new obj.constructor() //保持继承链
    	for (var key in obj) {
    		if (obj.hasOwnProperty(key)) {
    			//不遍历其原型链上的属性
    
    			var val = obj[key]
    
    			newObj[key] = typeof val === 'object' ? arguments.callee(val) : val // 使用arguments.callee解除与函数名的耦合
    		}
    	}
    	return newObj
    }
    
    
  3. 展开运算符进行浅拷贝

    var arr1=[1,2,5,6,4];
    
    var arr2=[...arr1];
    
    arr1 == arr2      // false;
    
    arr1.push(8,9,9) // (8)[1, 2, 5, 6, 4, 8, 9, 9]
    
    arr2 // (5) [1, 2, 5, 6, 4]
    
    var arr3 = arr1
    
    arr3 // (8) [1, 2, 5, 6, 4, 8, 9, 9]
    
    arr1.push(12313,12313) // (10) [1, 2, 5, 6, 4, 8, 9, 9, 12313, 12313]
    
    arr3 // (10) [1, 2, 5, 6, 4, 8, 9, 9, 12313, 12313]
    
posted @ 2022-02-11 11:40  AvenCheung  阅读(42)  评论(0编辑  收藏  举报