快速理解js对象深浅拷贝知识点!json方法JQuery extend()方法原型链继承方法Object.assign()方法

js中实现对象拷贝有哪些方法!

首先说下浅拷贝与深拷贝区别

  • 浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象

  • 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

一json方法

  • JSON对象是深度克隆,方法是首先
  • JSON.stringfy()转换为json字符串,然后在JSON.parse()转为json数组

缺点 如果你拷贝的对象有函数,函数无法被拷贝下来

无法发拷贝copyObj对象原型链上的属性和方法

var obj1={
				x:1,
				y:{
					a:1,
					b:0,
					c:[1,2,3]
				}
			}
			
			var  obj2=obj1;
			console.log(obj2==obj1)
			// 相同引用 结果为true  复制对象指针 还指向同一对象
			var  obj3=JSON.parse(JSON.stringify(obj1))
			console.log(obj3==obj1)
			console.log(obj3)
			// 不同引用  结果为false  通过json方法复制地址不一样

二JQuery extend()方法

  • 拓展对象本身 在这个空间上增加新的函数
	var obj1={
				x:1,
				y:{
					a:1,
					b:0,
					c:[1,2,3]
				}
			}
			
			
			var  obj2=$.extend({},obj1)
			console.log(obj2==obj1)
			// 复制后地址不一样
			console.log(obj2)
------------结果------------
false
{x: 1, y: {…}}

三 object.create()方法

  • 复制对象存在在obj原型prototype中

 

  • 	var obj1={
    				x:1,
    				y:{
    					a:1,
    					b:0,
    					c:[1,2,3]
    				}
    			}
    			
    			
    			var  obj2=Object.create(obj1)
    			console.log(obj2==obj1)
    			// 复制后地址不一样
    			console.log(obj2)
    			
    -------------结果-----------
    false
     {}
    __proto__: Object

     

四for循环遍历方法

  •  浅拷贝:
     只是拷贝了基本类型的数据;然而引用类型数据, 只是复制了指针,复制后也是会发生引用。
     除了这个是浅拷贝,本文章介绍的其他方法都是深拷贝。

			var  obj2={}
			for(var  i  in  obj1){
				// for in  会遍历对象属性  包括实例原型的属性需要访问  可枚举属性
				obj2[i]=obj1[i]
				
			}
			console.log(obj2)
			
			obj2.y.c.push(4)
			// 给obj2新数组添加一个元素2  会同步反应到旧数组中
			console.log(obj2.y.c)
			console.log(obj1.y.c)
			// 浅拷贝  就是复制地址 修改内存数据
--------结果---------
{x: 1, y: {…}}
(4) [1, 2, 3, 4]
(4) [1, 2, 3, 4]
  • 深拷贝
  •  深拷贝, 就是遍历那个被拷贝的对象。判断对象里每一项的数据类型。如果不是对象类型, 就直接赋值, 如果是对象类型, 就再次调用递归的方法去赋值。
var obj1 = {
				x: 1,
				y: {
					a: 1,
					b: 0,
					c: [1, 2, 3]
				}
			}

			function getClass(o) {
				// 判断数据类型
				return Object.prototype.toString.call(o).slice(-8, 1)

			}


			function deepCopy(obj1) {
				var result, oClass = getClass(obj1);
				// 声明一个result   oClass=getclass(obj1)判断结果


				if (oClass == "Object") result = {};
				// 如果说是判断是对象  继续遍历
				else if (oClass == "Array") result = {}
				// 如果传入判断是数组  继续遍历
				else   return obj1 
				// 如果是基本类型  直接返回
				
				
				for(var  i  in  obj1){
					
					var  copy=obj1[i]
					
					if(getClass(copy)=="Object")  result[i]=deepCopy(copy)
                     //递归方法  对象继续变量obj[i]  下一级还是对象   就obj1[i][i]					
					else if(getClass(copy)=="Array")  result[i]=deepCopy(copy)
					else  result[i]=copy
					// 基本数据类型赋值给属性
				}
				
				return  result
			}
			
			var obj2=deepCopy(obj1)
			console.log(obj2)
--------结果---------------
{x: 1, y: {…}}x: 1y: {a: 1, b: 0, c: Array(3)}__proto__: Object
  • 五. 原型链继承方法

  • 	function  Father(){
    				
    				this.say="hi"
    				this.fn=function(){
    					
    					return this.say
    				}
    				
    				
    			}
    			
    			Father.prototype.eat=function(){
    				console.log("吃")
    			}
    			
    			function  Son(){
    				this.play=function(){
    					console.log("play game")
    				}
    			}
    			
    			//通过原型  继承  父类  公共属性
    			Son.prototype=new  Father()
    			var  s=new  Son()
    			
    			
    			console.log(s)
    			console.log(s.say)
    			console.log(s.fn())
    	
    --------------结果------------
    Son {play: ƒ}
     hi
     hi
    			

     

六Object.assign()方法

语法:Object.assign(target, …sources)
(1)target—目标对象
(2)sources—源对象

如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。
Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()和Object.defineProperty() 。
String类型和 Symbol 类型的属性都会被拷贝。
在出现错误的情况下,例如,如果属性不可写,会引发TypeError,如果在引发错误之前添加了任何属性,则可以更改target对象。
注意:Object.assign 不会在那些source对象值为 null 或 undefined 的时候抛出错误。

const targetObj = { a1: 1 };
const sourceObj1 = { a2: 2 };
const sourceObj2 = { a3: 3 };
Object.assign(targetObj, sourceObj1, sourceObj2);
target // {a1:1, a2:2, a3:3}

Object.assign()拷贝的是属性值,假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。

let obj1 = { a: 0 , b: { c: 0}}; 
let obj2 = Object.assign({}, obj1); 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 
 
obj1.a = 1; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 
 
obj2.a = 2; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
 
obj2.b.c = 3;  // 此时两个对象下b指向的是一个位置。
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}} 
 
// 可以实现深拷贝
obj1 = { a: 0 , b: { c: 0}}; 
let obj3 = JSON.parse(JSON.stringify(obj1));  // 此时相当于重建了对象
obj1.a = 4; 
obj1.b.c = 4; 
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}

合并具有相同属性的对象,属性被后续参数中具有相同属性的其他对象覆盖

// 普通合并对象
const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };
 
const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。
 
// 此时对象之间有相同值
const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };
 
const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }   后边的覆盖前边的

继承属性和不可枚举属性是不能拷贝的

const obj = Object.create({foo: 1}, { //  根据Object.create()foo是个继承属性。
    bar: {
        value: 2  // 根据这个写法,bar 是个不可枚举属性 。
    },
    baz: {
        value: 3,
        enumerable: true  // baz 是个自身可枚举属性。
    }
});
 
const copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }

五、for循环遍历方法

1.浅拷贝:

只是拷贝了基本类型的数据;然而引用类型数据, 只是复制了指针,复制后也是会发生引用。 除了这个是浅拷贝,本文章介绍的其他方法都是深拷贝。

var obj = {
    x: 1,
    y: {
        a: 1,
        b: 0,
        c: [1, 2, 3]
    }
};

var obj2 = {};

for (var i in obj) { //for in 会遍历对象的属性,包括实例中和原型中的属性。(需要可访问,可枚举属性)
    obj2[i] = obj[i];
}
console.log(obj2);

obj2.y.c.push(4); //给新数组添加一个元素4,会同步反映在新旧数组中
console.log(obj2.y.c); // [1,2,3,4]
console.log(obj.y.c); // [1,2,3,4]  浅拷贝只是复制了地址,修改是内存中的数据

2.深拷贝:

遍历那个被拷贝的对象。判断对象里每一项的数据类型。如果不是对象类型, 就直接赋值, 如果是对象类型,就再次调用递归的方法去赋值。

var obj = {
    x: 1,
    y: {
        a: 1,
        b: 0,
        c: [1, 2, 3]
    }
};

function getClass(o) { //判断数据类型
    return Object.prototype.toString.call(o).slice(8, -1);
}

function deepCopy(obj) {
    var result, oClass = getClass(obj);

    if (oClass == "Object") result = {}; //判断传入的如果是对象,继续遍历
    else if (oClass == "Array") result = []; //判断传入的如果是数组,继续遍历
    else return obj; //如果是基本数据类型就直接返回

    for (var i in obj) {
        var copy = obj[i];

        if (getClass(copy) == "Object") result[i] = deepCopy(copy); //递归方法 ,如果对象继续变量obj[i],下一级还是对象,就obj[i][i]
        else if (getClass(copy) == "Array") result[i] = deepCopy(copy); //递归方法 ,如果对象继续数组obj[i],下一级还是数组,就obj[i][i]
        else result[i] = copy; //基本数据类型则赋值给属性
    }

    return result;
}

var obj2 = deepCopy(obj);
console.log(obj2);

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值