Js复制对象/克隆对象 Js浅拷贝与深拷贝 浅拷贝和深拷贝的实现方法

Js复制对象/克隆对象 Js浅拷贝与深拷贝 浅拷贝和深拷贝的实现方法

前言

学习Js克隆一个对象,作为准备工作,需要理解Js中的数据类型和按值传递:Js中的数据类型和按值传递

浅拷贝最后两种方法不理解的话,可以读es5替换函数中的this的方法
Js中的prototype、__proto__和constructor

1. 浅拷贝

1.1. 赋值和浅拷贝

概念:

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是原始类型,拷贝的就是原始类型的值;如果属性是引用类型,拷贝的就是内存地址 。

代码示例:

var student={
    
    
    name:"Lily",
    age:15,
    sex:"女",
    friends:["Jack","Rose","Ben"]
}
var obj1=student;
function clone(obj){
    
    
    var newObj={
    
    };
    for(var key in obj){
    
    
        newObj[key]=obj[key]
    }
    return newObj;
}
var obj2=clone(student)
obj1.name="Tom";
obj2.sex="男";
obj2.friends[0]="Lilei";
console.log(student.name) //Tom 
console.log(student.age) //15
console.log(student.friends) //["Lilei", "Rose", "Ben"]

解析:

i. 赋值:

上面一段代码,obj1由赋值得到,student变量中保存着所创建对象的地址,根据按值传递,我们知道,obj1变量中保存的是student所存地址的副本,这两个地址指向同一个实例化对象,无论哪个对象发生改变,都改变了这个实例化对象,两个对象是联动的。

ii. 浅拷贝:

a. 重新创建一个新对象,逐个拷贝源对象的属性;

b. 属性值是原始类型数据,拷贝的是原始类型的值的副本,原始类型的属性在新对象和源对象之间互不影响

c. 属性值是引用类型数据,拷贝的是地址,如果其中一个的地址发生改变,就会影响到另外一个对象

1.2. 浅拷贝的方法

1.2.1. Object.assign()

Object.assign()方法可以将任意多个源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象

var student={
    
    
    name:"Lily",
    age:15,
    sex:"女",
    friends:["Jack","Rose","Ben"]
}
var obj3=Object.assign({
    
    },student)
console.log(obj3.name) //LilY
1.2.2. 展开运算符…(Es6新特性)
var student={
    
    
    name:"Lily",
    age:15,
    sex:"女",
    friends:["Jack","Rose","Ben"]
}
var obj4={
    
    ...student}
console.log(obj4.name) //LilY
1.2.3. 强行调用数组的concat方法
var student={
    
    
    name:"Lily",
    age:15,
    sex:"女",
    friends:["Jack","Rose","Ben"]
}
var obj5=Array.prototype.concat.call({
    
    },student)
console.log(obj5) //{name: "Lily", age: 15, sex: "女", friends: Array(3)}  
1.2.4. 强行调用数组的slice方法
var student={
    
    
    name:"Lily",
    age:15,
    sex:"女",
    friends:["Jack","Rose","Ben"]
}
var obj6=Array.prototype.slice.call({
    
    },student)
console.log(obj6) //{name: "Lily", age: 15, sex: "女", friends: Array(3)}   

2.深拷贝

概念

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

2.1. 深拷贝与浅拷贝对比

浅拷贝与深拷贝对比

2.2. 深拷贝的实现方式

2.2.1. JSON.parce(JSON.stringify())
var student={
    
    
    name:"Lily",
    age:15,
    sex:"女",
    friends:["Jack","Rose","Ben"]
}
var obj7=JSON.parse(JSON.stringify(student))
console.log(obj7) //{name: "Lily", age: 15, sex: "女", friends: Array(3)}
obj7.friends[0]="Alice"
console.log(student.friends[0]) //Jack 未影响源对象

利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的内存空间,实现深拷贝。

这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对

象),对象中的方法克隆不到。

var student={
    
    
    name:"Lily",
    age:15,
    sex:"女",
    friends:["Jack","Rose","Ben"],
    say:function(){
    
    
        console.log("hello")
    }
}
var obj7=JSON.parse(JSON.stringify(student))
console.log(obj7) //{name: "Lily", age: 15, sex: "女", friends: Array(3)} 没有say方法
2.2.2.手写递归

递归方法实现深度克隆原理:遍历对象直到最内层都是原始数据类型,然后再去复制,就是深度拷贝
有种特殊情况需注意就是对象存在循环引用的情况,即对象的属性直接的引用了自身的情况,解决循环引用问题,我们可以额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系,当需要拷贝当前对象时,先去存储空间中找,有没有拷贝过这个对象,如果有的话直接返回,如果没有的话继续拷贝。

function deepClone(obj, hash = new WeakMap()) {
    
    
  if (obj === null) return obj; 
  // 如果是null或者undefined我就不进行拷贝操作
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
  if (typeof obj !== "object") return obj;
  // 是对象的话就要进行深拷贝
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
  hash.set(obj, cloneObj);
  for (let key in obj) {
    
    
    if (obj.hasOwnProperty(key)) {
    
    
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}
let obj = {
    
     name: 1, address: {
    
     x: 100 } };
obj.o = obj; // 对象存在循环引用的情况
let d = deepClone(obj);
obj.address.x = 200;
console.log(d);

未完待续…待补充

参考文章:
如何写出一个惊艳面试官的深拷贝?(找不到文章的网址,只能贴个题目)
一文读懂 javascript 深拷贝与浅拷贝(公众号推文,找不到文章的网址,只能贴个题目)

猜你喜欢

转载自blog.csdn.net/Amazing_rabbit/article/details/108648270