談起拷貝,在咱們實際的開發應用中很是多,對於基本類型而言,在變量進行賦值的時候,會自動爲其開闢一個新的變量存儲空間,而對於複雜數據類型而言(對象),賦值操做則須要思考更多;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);
複製代碼
操做 | 第一層基本數據類型改變 | 第二層爲引用類型改變 |
---|---|---|
賦值 | 原數據會改變 | 原數據會改變 |
淺拷貝 | 原數據不會改變 | 原數據會改變 |
深拷貝 | 原數據不會改變 | 原數據不會改變 |
文章是很久以前進行總結的,相關參考資料因爲當時沒標註,因此沒法找到連接了,但願理解;😂