关于对象的深浅克隆
-
首先在我们的认知中,存在这复合数据类型,和基本数据类型。基本数据类型在使用的时候是进行传值调用址,复合数据类型是进行一个传址调用。
-
所以我们在对象克隆的时候就会错误的将同一个地址赋值到我们需要使用的一个新的变量之上,这样我们在使用的时候。修改值得时候就会直接在地址中修改,所以就会影响到原数组,这时候我们就可能会需要用到对象得深克隆
-
首先我先介绍几种浅拷贝得方法来避免使用。
- Object.assign(),这是ES6中合并对象得方法,这是把第一个参数之后得参数全部复制到第一个对象中,这样可以实现第一层的拷贝
- 然后我们也可以利用ES6的展开运算符来实现对第一层的浅拷贝。
-
接着我们就介绍一下深拷贝了
- 最常用的一种拷贝方式
JSON.parse(JSON.stringify(object))
该方法引发的问题:
- 会忽略undefined
- 会忽略到symbol
- 不能序列化函数
- 不能解决循环引用的对象
- 我们还可以使用lodash中的
cloneDeep
函数来进行对象的深克隆 - 最后我们可以使用自己的递归方法来进行深克隆。
1.首先我们先判断传入的对象类型,然后我们根据这个类型来创建target
2.我们在获取源对象所有的属性名,包括不可枚举的属性
3.之后我们遍历所有的属性名
4.我们获取每个属性的描述对象
5.在判断该属性是否是基础数据类型,如果是,我们就直接将当前属性放入目标对象中
6.如果不是的话,我们就根据该属性,重新创建一个引用
7.因为DOM非常的特殊,所以我们先判断该对象是否是DOM类型,如果是的话我们直接复制当前dom
8.如果不是DOM,我们来判断当前属性中原型的构造
9.我们根据构造来创建一个类型
10.之后我们判断该属性的某个描述对象是否存在,如果存在,我们就给他们添加,
11.这些完毕,我们在把当前引用传入当前函数,进行递归操作。
最后我们将复制的后的值,返回出去function cloneObj(source, target) { var list = ["string", "number", "null", "undefined", "boolean", "function"] if (target === undefined) { // 先判断是不是dom节点,是就可以去直接clone节点 if (HTMLElement.prototype.isPrototypeOf(source)) { target = source.cloneNode(false) } else { target = new source.constructor() } } // 获取对象的所有属性包括,包扩不可枚举的属性 var names = Object.getOwnPropertyNames(source) for (var i = 0; i < names.length; i++) { var desc = Object.getOwnPropertyDescriptor(source, names[i]) if (list.includes(typeof desc.value)) { Object.defineProperty(target, names[i], desc); } else { var t; if(HTMLElement.prototype.isPrototypeOf(desc.value)) { t = desc.value.cloneNode(false) } else { switch (desc.value.constructor) { case RegExp: t = new RegExp(desc.value.source, desc.value.flags) break; case Date: t = new Date(desc.value) break; case Symbol: t = Symbol break; case Set: t = new Set(desc.value.values()) break; case Map: t = new Map(desc.value.entries()) break default: t = new desc.value.constructor(); break; } } var o = {} o.value = t; desc.enumerable && (o.enumerable = desc.enumerable) desc.writable && (o.writable = desc.writable) desc.configurable && (o.configurable = desc.configurable) desc.set && (o.set = desc.set) desc.get && (o.get = desc.get) Object.defineProperty(target, names[i], o) console.log(desc.value,t) cloneObj(desc.value, t) } } return target }
- 最常用的一种拷贝方式
网友评论