谈起拷贝,在咱们实际的开发应用中很是多,对于基本类型而言,在变量进行赋值的时候,会自动为其开辟一个新的变量存储空间,而对于复杂数据类型而言(对象),赋值操做则须要思考更多;es6
对象的拷贝分为深拷贝
和浅拷贝
,其主要的深和浅,主要是对象中包含的对象类型;以下所示,对obj
的拷贝区分主要在offer
中;数组
var obj = {
name:'mfy',
age:18,
offer:{
company:'~',
jobs:'sercert'
}
}
复制代码
浅拷贝主要解决对象中引用的问题; 浅拷贝是按位拷贝对象,他会建立一个新对象,这个对象有着原始对象属性值的一份精确拷贝。markdown
所以若是其中一个对象改变了这个地址,就会影响到另外一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员一次拷贝),即只复制对象空间而不复制资源。函数
var a = {
age:22,
name:'mfy',
data:{
bane:'33',
defa:'333,
}
}
//b对a进行浅拷贝后
var b = a;
复制代码
Object.assgin()
方法能够把任意多个的原对象自身的可枚举属性拷贝给目标对象,而后返回目标对象。可是Object.assgin()
进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象自己。ui
var a ={
age:22,
data:{
name:'3333',
}
}
var b = Object.assign({},a)
b.data.name =3;
b.age =333
console.log(b)
console.log(a)
复制代码
当咱们修改经过Object.assgin()
的方法建立的对象的内部属性值的时候,对象中的基本类型是新开辟的空间存储,而复杂的类型即对象类型,则仍是一个直接引用的关系,修改b会影响到aspa
首先咱们要清楚的是Object.create()
的方法使用prototype
var obj = Object.create({a:3})
console.log(obj)
var obj1 = Object.create(null)
console.log(obj1)
复制代码
var obj2 = Object.create({a:3},{
foo: {
writable: true,
configurable: true,
value: 'hello'
},
})
复制代码
其实经过咱们传递一个参数的时候,引用类型所在的位置进行判断,在__proto__
的属性上,很是相似于new Object进行建立3d
var a = {
age: 22,
data: {
name: '3333',
}
}
var c = Object.create(a)
c.age = 666
c.data.name = 444
a.age = '18'
console.log('a', a)
console.log('c', c)
复制代码
咱们可以发现变量c中的__proto__
所使用的对象的引用和a对象的引用是一个code
__proto__
的age属性也跟着变化在es6中新增的方法;orm
var o = { age: 333, data: { name: 3232 } }
var d = { ...o }
d.data.name = 'd修更名字'
console.log('o',o)
console.log('d',d)
复制代码
是对数组中的对象进行的一个赋值;
var arr =[12,2323,{name:2}]
var arr2=arr.concat();
arr2[2].name =44
console.log(arr)
console.log(arr2)
复制代码
Array.prototype.concat
中对于数组的拷贝,其实也是浅拷贝,数组中某个项的对象是存在引用关系的
实现的原理和上面一致,都是复制基本属性,里面的对象引用仍是在一块儿的 只是复制了一个数组,不会需求原数组中的数据,能够当成特殊的对象;
深拷贝会另外创造一个如出一辙的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象; 当b进行引用赋值a的时候,会从新生成一个新的地址引用,不会和a共用一个地址;这样a/b互相改变值的时候不会互相影响;
JSON.parse(JSON.string(obj))
是我常常在工做用到的方法,固然也是区分情景的;
var obj = {
offer: {
money: 13133,
company: "一代大神"
},
name: 'mfy'
}
var obj2 = JSON.parse(JSON.stringify(obj));
obj2.offer.money = '修改为自定义的money'
console.log('obj',obj)
console.log('obj2',obj2)
复制代码
虽然JSON.parse(JSON.string(obj))
给咱们提供了很大的便捷度,可是也是存在缺点的,
obj2
中是不存在obj1
中所包含的函数的
var obj = {
fun:function(){console.log("我是函数")},
name: 'mfy'
}
var obj2 = JSON.parse(JSON.stringify(obj));
console.log('obj',obj)
console.log('obj2',obj2)
复制代码
var a = Symbol('hh',33);
var obj = {
name: 'mfy',
age:undefined,
a,
}
var obj2 = JSON.parse(JSON.stringify(obj));
console.log('obj',obj)
console.log('obj2',obj2)
复制代码
// 未作细化
function deepMerge(obj) {
//类型校验省略
var target = {};
for (var key in obj) {
let itemObj = obj[key];
if (typeof itemObj == 'object') {
target[key] = deepMerge(itemObj)
} else {
target[key] = obj[key]
}
}
return target;
}
var obj3 = {age:18,name:'mfy',offer:{company:'XXX',jobs:333}}
var obj4 = deepMerge(obj3);
obj4.offer.company="big company"
console.log('obj4',obj4)
console.log('obj3',obj3)
复制代码
obj4
通过深拷贝后,再次修改内部对象类型,不会影响到obj3
,此时两个变量的存储方式,存储空间是无任何关联的
在lodash
库中也是提供了方法,去深拷贝,其原理基本和2一致
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);
复制代码
操做 | 第一层基本数据类型改变 | 第二层为引用类型改变 |
---|---|---|
赋值 | 原数据会改变 | 原数据会改变 |
浅拷贝 | 原数据不会改变 | 原数据会改变 |
深拷贝 | 原数据不会改变 | 原数据不会改变 |
文章是很久以前进行总结的,相关参考资料因为当时没标注,因此没法找到连接了,但愿理解;😂