前端的开发过程中,很多时候都需要对数据进行处理,而拷贝则可以获取一个独立的数据进行修改,不造成篡改数据的混乱。
在js中有 3 中数据拷贝的方式
赋值
基本数据类型赋值 则是开辟一块新的空间存储两者之间互不相干
引用数据类型 指向同一个对象,相互之间会影响
而深拷贝这可以解决这个问题
浅拷贝:对于基本数据类型---是对值的复制,对于引用数据类型---是对对象的地址进行复制。浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
对象浅拷贝
// 语法
1、Object.assign({},originalObj) // 将原对象自身可以枚举的属性拷贝给新对象,对对象则是引用地址,后返回新对象
let obj = {a:"a",b:{c:"c"}}
// 如果 newObj["b"]的值被修改也就等同于 obj["b"]的值被修改 因为两种引用同一个地址
let newObj = Object.assign({},obj) //{a:"a",b:{c:"c"}}
特点:
1、会拷贝源对象自身的属性(不拷贝继承属性)
2、不会拷贝对象不可枚举的属性
3、undefined和null无法转换成对象,它们不能成为Object.assign的参数,但可以作为源对象
4、属性名为Symbol值的属性,可以被拷贝
数组拷贝
1、数组的 concat() 方法 //合并返回新的数组
let arr1 = [1,2,3,4]
let newarr = arr1.concat() //[1,2,3,4]
2、数组的 slice() 方法 //截取返回新的数组
let arr1 = [1,2,3,4]
let newarr = obj.slice() //[1,2,3,4]
扩展运算符
let arr = {l:[1,2,3],age:"18"}
let newarr = {...arr} //{l:[1,2,3],age:"18"}
手动封装
function cloneShallow(source) {
var target = {};
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
//会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)
target[key] = source[key];
}
}
return target;
}
深拷贝深拷贝会重新开辟一个栈空间,同对象对应不同地址,修改一个属性另一个对象不变。
JSON.parse(JSON.stringfy(obj))
利用现代浏览器支持的JSON对象做一次中转,实现深度克隆。
优点:简单便捷
缺点:不会对函数,symbol进行转换(相当于删除了),新生成的对象不会显示
对象属性指向对象本身(类似window.window/obj.name = obj)不能使用这种方式进行深拷贝的,否则会报错的(不能将这种循环的结构转成JSON)
目前最优解是通过递归
//判断函数
function isObject(value) {
const valueType = typeof value
return (value !== null) && (valueType === "object" || valueType === "function")
}
function deepClone(originValue) {
// 判断是否是一个Set类型
if (originValue instanceof Set) {
return new Set([...originValue])
}
// 判断是否是一个Map类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
// 判断如果是Symbol的value, 那么创建一个新的Symbol
if (typeof originValue === "symbol") {
return Symbol(originValue.description)
}
// 判断如果是函数类型, 那么直接使用同一个函数
if (typeof originValue === "function") {
return originValue
}
// 判断传入的originValue是否是一个对象类型
if (!isObject(originValue)) {
return originValue
}
// 判断传入的对象是数组, 还是对象
const newObject = Array.isArray(originValue) ? []: {}
for (const key in originValue) {
newObject[key] = deepClone(originValue[key])
}
// 对Symbol的key进行特殊的处理
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for (const sKey of symbolKeys) {
// const newSKey = Symbol(sKey.description)
newObject[sKey] = deepClone(originValue[sKey])
}
return newObject
}