浅拷贝是其属性与拷贝源对象的属性共享相同引用,当你更改源或副本时,也可能(可能说的是只针对引用数据类型)导致其他对象也发生更改。
特性:
注意var people1 = people不是浅拷贝。只是对内存地址进行赋值,people1 === people 返回true,这种不是浅拷贝
- // 这个种方式不是浅拷贝
- var people = {
- name: 'allen'
- }
-
- // 这里只是对内存地址进行赋值,people1 === people 返回true,这种不是浅拷贝
- var people1 = people
- people1.name = 'jason'
浅拷贝:会新创建一个对象,对源对象的属性进行拷贝,使两者共享同一个地址。obj === obj2返回false。比如:var obj2 = Object.assign({}, obj)

说明:Object.assign()是浅拷贝,会生成一个新的对象。浅拷贝对于基本数据类型a,会重新单独开辟一份空间进行存储, 而对于引用数据类型b拷贝的是其内存地址,所以obj2和obj对于拷贝后的b是共用一份内存地址。所以如果修改obj2中b的b1的值,则obj中的b1的值也会改变
创建一个对象,会将源对象放到新对象的原型上(即会将obj对象放到obj2的原型上),返回一个新的对象。
- var obj = {a: 1}
- var obj2 = Object.create(obj)
- obj.a = 2 //修改基本数据类型,源对象也会改变
- console.log(obj === obj2); //false
- console.log(obj,obj2);

将对象属性进行合并,并返回新的对象,遇到重名对象会进行覆盖
- var obj = {
- a: 1,
- b: {
- b1: 1
- }
- }
- var obj2 = Object.assign({}, obj)
- obj.a = 2
- obj.b.b1 = 2
-
- console.log(obj === obj2);
- console.log(obj, obj2);
结果:源对象基本数据类型值没有改变,引用数据用的同一个会改变

- var obj = {
- a: 1,
- b: {
- b1: 1
- }
- }
-
- var obj2 = {...obj};
- obj2.a = 3;
- obj2.b.b1 = 2;
-
- console.log(obj === obj2);
- console.log(obj, obj2);
结果:同上

深拷贝是指其属性与其拷贝的源对象的属性不共享相同的引用,当你更改源或副本时,可以确保不会导致其他对象也发生更改
原理:通过改变数据类型的形式进行深拷贝,JSON.stringify()将对象序列化成字符串,而JSON.parse()将字符串转为对象。注意不是JSON.stringify()是两个方法组合使用
- var obj = {
- a: 1,
- b: {
- b1: 1
- }
- }
- var obj1 = JSON.parse(JSON.stringify(obj))
- obj1.a = 2
- obj1.b.b1 = 2
- console.log(obj === obj2);
- console.log(obj, obj2);
结果:基本数据类型和引用数据类型的改变都不会印象源对象

cdn地址 : https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js
- import _ form "lodash";
-
- var obj = {
- a: 1,
- b: {
- b1: 1
- }
- }
- var obj1 = _.cloneDeep(obj)
- obj1.a = 2
- obj1.b.b1 = 2
- var obj = {};
- obj.a = obj;
- console.log(obj);
对象可以一直展开,无限嵌套,无限循环

- function deepClone(obj) {
- console.log(typeof obj);
-
- // 判断如果为null,不等于字符串的object,function, 为Date类型,RegRex类型则直接返回
- if (obj === null || typeof obj !== 'object' || typeof obj === 'function' || obj instanceof Date || obj instanceof RegExp) {
- return obj;
- }
-
- if (obj instanceof Object) {
- const newObj = {};
- for (let key in obj) {
- newObj[key] = deepClone(obj[key]);
- }
- // 注意是最后return不是在for循环中returnnewObj[key]
- return newObj;
- }
- }
-
- var obj = {
- a: 1,
- b: {
- b1: 1
- }
- }
- var obj2 = deepClone(obj);
- obj2.a = 2;
- obj2.b.b1 = 2
- console.log(obj === obj2);
- console.log(obj, obj2);
- function deepClone(obj) {
- // 判断如果为null,不等于字符串的object,function, 为Date类型,RegRex类型则直接返回
- if (obj === null || typeof obj !== 'object' || typeof obj === 'function' || obj instanceof Date || obj instanceof RegExp) {
- return obj;
- }
-
- if (obj instanceof Set) { //对于Set数据结构(for of 循环;newSet.add(val))
- const newObj = new Set();
- for (let val of obj) {
- newObj.add(deepClone(val));
- }
- return newObj;
- } else if (obj instanceof Map) { //对于Map数据结构(for of循环 map.set(key,val))
- const newObj = new Map();
- for (let [key, val] of obj) {
- newObj.set(key, deepClone(val));
- }
- return newObj;
- } else if (obj instanceof Array) { //对于数组数据结构(使用forEach进行循环push进行添加)
- const newObj = [];
- obj.forEach(item => {
- newObj.push(deepClone(newObj[item]));
- });
- return newObj
- } else if (obj instanceof Object) {
- const newObj = {};
- for (let key in obj) {
- newObj[key] = deepClone(obj[key]);
- }
- // 注意是最后return不是在for循环中returnnewObj[key]
- return newObj;
- } else {
- return obj;
- }
- }
-
- var newMap = new Map();
- newMap.set('key1', 12);
- newMap.set('key2', 13);
-
- var newSet = new Set();
- newSet.add('11');
- newSet.add('22');
-
- var obj = {
- a: 1,
- b: {
- b1: 1
- },
- c: {
- c1: [1, 2, 3]
- },
- d: newMap,
- f: newSet
- }
- var obj2 = deepClone(obj);
- obj2.a = 2;
- // 基本数据类型修改值
- obj2.b.b1 = 2
- // 数组改变值
- obj2.c.c1 = [2, 3, 4];
- // map集合修改key1
- obj2.d.set('key1','更改后的key1');
- // Set集合增加一个
- obj2.f.add('set集合增加的值');
- console.log(obj === obj2);
- console.log(obj, obj2);

如果有循环引用,使用方式二深拷贝处理,会一直循环导致内存溢出。map = new WeakMap()用于判断是否已经有过相同引用

- function deepClone(obj, map = new WeakMap()) {
- // 判断如果为null,不等于字符串的object,function, 为Date类型,RegRex类型则直接返回
- if (obj === null || typeof obj !== 'object' || typeof obj === 'function' || obj instanceof Date || obj instanceof RegExp) {
- return obj;
- }
-
- // 循环引入处理(如果obj下的key的值为obj本身,则循环将obj的值设置到map的key中)
- // WeakMap的key只能是对象,Set、Map、Array、Object每个都设置map.set(obj,newObj);是因为每种数据结构都有可能存在循环引用
- if (map.get(obj)) {
- return map.get(obj);
- }
-
- if (obj instanceof Set) { //对于Set数据结构(for of 循环;newSet.add(val))
- const newObj = new Set();
- map.set(obj, newObj);
- for (let val of obj) {
- newObj.add(deepClone(val, map));
- }
- return newObj;
- } else if (obj instanceof Map) { //对于Map数据结构(for of循环 map.set(key,val))
- const newObj = new Map();
- map.set(obj, newObj);
- for (let [key, val] of obj) {
- newObj.set(key, deepClone(val, map));
- }
- return newObj;
- } else if (obj instanceof Array) { //对于数组数据结构(使用forEach进行循环push进行添加)
- const newObj = [];
- map.set(obj, newObj);
- obj.forEach(item => {
- newObj.push(deepClone(newObj[item], map));
- });
- return newObj
- } else if (obj instanceof Object) {
- const newObj = {};
- map.set(obj, newObj); //此处设置后,后面newObj即使更改,map内存地址使用的是一个所以map的值也会跟着变
- for (let key in obj) {
- newObj[key] = deepClone(obj[key], map);
- }
- // 注意是最后return不是在for循环中returnnewObj[key]
- return newObj;
- } else {
- return obj;
- }
- }
-
-
- // 循环引入
- var obj3 = {};
- obj3.a = obj3;
- var obj4 = deepClone(obj3);
- obj4.b = obj4;
- console.log(obj3 === obj4);
- console.log(obj3, obj4);
