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


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

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

浅拷贝最后两种方法涉及到了继承和es5新特性中的call方法,可以读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. 赋值:

上面一段代码,student变量中保存着所创建对象的地址,obj1由赋值得到,根据按值传递,我们知道,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. 深拷贝与浅拷贝对比

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

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处理后,JSON.stringify()方法在处理undefined、任意的函数以及 symbol 值时,作为非数组对象的属性值时会被忽略,作为数组对象中的属性值时,会被转换成 null。函数、undefined 被单独转换时,会返回 undefined。

使用JSON.parce(JSON.stringify())克隆非数组对象,源对象中的方法被忽略

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方法被忽略

使用JSON.parce(JSON.stringify())克隆数组对象,源对象中的方法被转换成null

var arr= [1,2,3,function say(){console.log("hello")}];
var obj=JSON.parse(JSON.stringify(arr));
console.log(arr,obj)

Js复制对象/克隆对象  Js浅拷贝与深拷贝 浅拷贝和深拷贝的实现方法
这里列举了一些最常用情况下的弊端,其他方面的弊端可参考JSON.stringify()

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);

解析:

WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。
方法:

WeakMap.prototype.delete(key)
移除key的关联对象。执行后 WeakMap.prototype.has(key)返回false。
WeakMap.prototype.get(key)
返回key关联对象, 或者 undefined(没有key关联对象时)。
WeakMap.prototype.has(key)
根据是否有key关联对象返回一个Boolean值。
WeakMap.prototype.set(key, value)
在WeakMap中设置一组key关联对象,返回这个 WeakMap对象

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

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

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

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » Js复制对象/克隆对象 Js浅拷贝与深拷贝 浅拷贝和深拷贝的实现方法
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏