1.浅拷贝
浅拷贝是指,一个新的对象对原始对象的属性值进行精确地拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值(不会互相影响);如果拷贝的是引用数据类型,拷贝的就是内存地址。如果其中一个对象的引用内存地址发生改变,另一个对象也会发生变化。
浅拷贝对象方法:
1.Object.assign: es6中Object提供的合并对象的方法:
let target = {a: 1}; //目标对象可以为{}
// 要拷贝的对象
let object2 = {b: {d : 2}};
let object3 = {c: 3};
Object.assign(target, object2, object3);
console.log(target); // {a: 1, b: {d : 2}, c: 3}
注意点:
-
如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性;
-
如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回;
-
因为
null
和undefined
不能转化为对象,所以第一个参数不能为null
或undefined
,否则会报错; -
它不会拷贝对象的继承属性,不会拷贝对象的不可枚举的属性,可以拷贝 Symbol 类型的属性。 2.扩展运算符:
扩展运算符可以在构造字面量对象的时候,进行属性的拷贝。
let obj1 = {a:1,b:{c:1}}
let obj2 = {...obj1};
// 修改obj1中的基础类型a的值
obj1.a = 2;
console.log(obj1); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}} a是基础类型,不会被影响
obj1.b.c = 2;
console.log(obj1); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}} b为引用类型 源对象司改后也跟着改变
3.手写浅拷贝:
// 浅拷贝的实现;
function simpleClone(obj) {
// 只拷贝对象
if (obj && typeof obj !== 'object') return
// 根据 obj 的类型判断是新建一个数组还是对象
let newObject = Array.isArray(obj) ? [] : {}
// 遍历 obj,只拷贝自身属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObject[key] = obj[key]
}
}
return newObject
}
hasOwnProperty()
方法,该方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性。所有继承了 Object 的对象都会继承到 hasOwnProperty()
方法。这个方法可以用来检测一个属性是否是对象的自身属性。
深拷贝
深拷贝对象的两个必要点:
1.切断引用(拷贝生成的对象跟原有的对象没有任何关系)
2.原对象中的所有属性要出现在拷贝的新对象中(下面拷贝的都是自身属性)
1.JSON.parse(JSON.stringify(o))实现深拷贝
let obj1 = {
a: 0,
b: {
c: 0,
},
}
let obj2 = JSON.parse(JSON.stringify(obj1))
obj1.a = 1
obj1.b.c = 1 //修改obj1引用类型的属性值
console.log(obj1) // {a: 1, b: {c: 1}}
console.log(obj2) // {a: 0, b: {c: 0}} obj2没有收到影响
利用JSON.stringify
将JavaScript
对象序列化成为JSON字符串),并将对象里面的内容转换成字符串,再使用JSON.parse
来反序列化,将字符串生成一个全新的JavaScript对象。\
注意点:
-
拷贝的对象中如果有函数,undefined,symbol,当使用过
JSON.stringify()
进行处理之后,都会消失。 -
无法拷贝不可枚举的属性;
-
无法拷贝对象的原型链;
-
拷贝 Date 引用类型会变成字符串;
-
拷贝 RegExp 引用类型会变成空对象;
-
对象中含有 NaN、Infinity 以及 -Infinity,JSON 序列化的结果会变成 null;
-
无法拷贝对象的循环应用,即对象成环 (
obj[key] = obj
)。
2.手写实现深拷贝
使用for in来遍历传入数据的属性值,如果值是基本类型就直接复制,如果是引用类型就进行递归调用该函数
let obj = {
uname: 'zkp',
age: {
b: {
c: 12,
},
},
studyArr: ['html5', 'css', 'js', 'vue','node.js'],
}
// deepClone
function deepClone(obj) {
if (!(obj instanceof Object)) return obj //不是对象实例,直接返回传入的数据
let target = Array.isArray(obj) ? [] : {} //根据obj类型初始化结果变量
for (let i in obj) {
if (obj.hasOwnProperty(i)) { // 判断是否是自身属性
//判断数据i的类型
if (typeof obj[i] === 'object') {
target[i] = deepClone(obj[i])
} else {
target[i] = obj[i]
}
}
}
return target
}
//验证:
let obj1 = deepClone(obj)
console.log(obj2)
// 结果:
// obj = { uname: 'zkp', age: { b: { c: 12,}},
// studyArr: ['html5', 'css', 'js', 'vue','node.js'], }
// 修改obj中引用类型的值
obj.studyArr.push('react')
obj.age.b.c = 20
console.log(obj);
// 结果:
// obj = { uname: 'zkp', age: { b: { c: 20,}},
// studyArr: ['html5', 'css', 'js', 'vue','node.js','react'], }
console.log(obj2);
// 结果:
// obj = { uname: 'zkp', age: { b: { c: 12,}},
// studyArr: ['html5', 'css', 'js', 'vue','node.js'], }
注意点:
这种方法只能对普通引用类型的值做递归复制,对于 Date、RegExp、Function 等引用类型不能正确拷贝;