深拷贝、浅拷贝、赋值
前端数据类型分为两种:值类型(String, Number, Boolean, Null, Undefined,Symbol)和引用类型(Array,Function,Object)。
值类型:数据存储在栈中。
引用类型:栈中存储的是对数据的引用地址(指针),真实数据存储的堆内存中。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
e.g 出去团建,员工门卡自己保管(值类型),老板门卡统一由秘书保管(引用类型)。
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。
浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝:会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
e.g旅行社来了个新顾客:
加入现有旅行团,多印一份该团的出行指南(浅拷贝)
给他单独设计一份出行规划(深拷贝)
赋值和浅拷贝的区别
赋值: 赋的其实是该对象的在栈中的地址,而不是堆中的数据。e.g 修改原/新对象值类型属性的取值后,另外一个对象值也会被改掉。
浅拷贝:浅拷贝拷贝的是指针而非值,是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址。e.g 修改修改原/新对象值类型属性的取值后,另外一个对象不受影响。
// 对象赋值 var obj1 = { 'name' : 'zhangsan', 'age' : '18', 'language' : [1,[2,3],[4,5]], }; var obj2 = obj1; obj2.name = "lisi"; obj2.language[1] = ["二","三"]; console.log('obj1',obj1) console.log('obj2',obj2)
// 浅拷贝 var obj1 = { 'name' : 'zhangsan', 'age' : '18', 'language' : [1,[2,3],[4,5]], }; var obj3 = shallowCopy(obj1); obj3.name = "lisi"; obj3.language[1] = ["二","三"]; function shallowCopy(myObj) { var dst = {}; for (var prop in myObj) { if (myObj.hasOwnProperty(prop)) { dst[prop] = myObj[prop]; } } return dst; } console.log('obj1',obj1) console.log('obj3',obj3)
浅拷贝实现方法:
1.Object.assign() 对象合并
let obj = {username: 'kobe'};
var initalObj = Object.assign({}, obj);
2.Array.prototype.concat() 数组合并
let arr = [1, 3, {username: 'kobe'}];
let arr2=arr.concat();
3.Array.prototype.slice() 数组提取
let arr = [1, 3, {username: ' kobe'}];
let arr3 = arr.slice();
//备注:不指定参数
4.解构赋值 {...obj }
深拷贝的实现方法:
1.JSON.parse(JSON.stringify()) 仅可以处理数组和对象,不能处理函数
2.使用函数库 Lodash
_.cloneDeep
用来做 Deep Copy
var _ = require('lodash'); var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] }; var obj2 = _.cloneDeep(obj1); console.log(obj1.b.f === obj2.b.f); // false
3.原生js实现深拷贝代码
// 深拷贝 function clone(data){ if(data instanceof Array){ // 传入为数组类型 var res = []; for(var i=0;i){ res[i] = clone(data[i]); } return res } else if(data instanceof Object){ // 传入为对象类型 var res = {}; for(var key in data){ res[key] = clone(data[key]); }
return res } else{ return data; // 传入为数字或字符串 } }