深淺拷貝
數(shù)據(jù)類型及特點(diǎn)
- 基本數(shù)據(jù)類型
Undefined, Null, Symbol, Boolean, String, Number
特點(diǎn):直接存儲(chǔ)在棧中的數(shù)據(jù) - 對(duì)象數(shù)據(jù)類型(引用數(shù)據(jù)類型)
特點(diǎn):棧中存儲(chǔ)的是對(duì)該對(duì)象的引用囱挑,真實(shí)的數(shù)據(jù)存儲(chǔ)在堆內(nèi)存中
引用數(shù)據(jù)類型在棧中存儲(chǔ)了指針谬俄,該指針指向堆中的該實(shí)體的起始地址酪呻,當(dāng)解釋器尋找引用值時(shí),
會(huì)首先檢索其在棧中的地址鸯绿,取得地址后從堆中獲得實(shí)體
深淺拷貝
深淺拷貝只針對(duì)Object或者Array這樣的引用數(shù)據(jù)類型
淺拷貝只復(fù)制指向?qū)ο蟮闹羔樀刂吩侣澹皇菑?fù)制對(duì)象本身日麸,新舊對(duì)象還是共享同一塊內(nèi)存杭煎。
深拷貝會(huì)創(chuàng)造另外一個(gè)一摸一樣的對(duì)象,新舊對(duì)象不共用同一塊內(nèi)存背率,修改新對(duì)象不會(huì)影響到舊對(duì)象话瞧。
淺拷貝與賦值的區(qū)別
var obj1 = {name: 'LiLy', age: '12', language: ['english', 'chinese', 'frech']}
-
賦值: 賦的是該對(duì)象在棧中的地址,而不是堆中的數(shù)據(jù)寝姿。
兩個(gè)對(duì)象指向的是同個(gè)存儲(chǔ)空間交排,無(wú)論哪個(gè)對(duì)象發(fā)生改變,其實(shí)改變的都是原對(duì)象会油,是聯(lián)動(dòng)的个粱。var obj2 = obj1 obj2.name = 'Lucy' obj2.language[0] = 'India' obj1 和 obj2 都是 { age: "12" language: (3) ["India", "chinese", "frech"] name: "Lucy" }
淺拷貝:按位拷貝對(duì)象古毛,它會(huì)創(chuàng)建一個(gè)對(duì)象翻翩,這個(gè)對(duì)象有著原始對(duì)象屬性值的一份精確拷貝。
如果屬性是基本數(shù)據(jù)類型稻薇,拷貝的就是基本類型的值嫂冻;
如果屬性是引用數(shù)據(jù)類型,拷貝的就是內(nèi)存地址塞椎。
因此如果其中一個(gè)對(duì)象改變了這個(gè)內(nèi)存地址桨仿,就會(huì)影響到另一個(gè)對(duì)象
function shallowCopy(src) {
var dst = {}
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop]
}
}
return dst
}
var obj3 = shallowCopy(obj1)
obj3.name = 'Bob'
obj3.language[0] = 'lan3'
obj3: {
age: "12"
language: (3) ["lan3", "chinese", "frech"]
name: "Bob"
}
obj1: {
age: "12"
language: (3) ["lan3", "chinese", "frech"]
name: "Lucy"
}
總結(jié):
-- | 和原數(shù)據(jù)是否指向同個(gè)對(duì)象 | 第一層數(shù)據(jù)為基本數(shù)據(jù)類型 | 元數(shù)據(jù)中包含子對(duì)象 |
---|---|---|---|
賦值 | 是 | 改變會(huì)使原數(shù)據(jù)一同改變 | 改變會(huì)使原數(shù)據(jù)一同改變 |
淺拷貝 | 否 | 改變不會(huì)使原數(shù)據(jù)一同改變 | 改變會(huì)使原數(shù)據(jù)一同改變 |
深拷貝 | 否 | 改變不會(huì)使原數(shù)據(jù)一同改變 | 改變不會(huì)使原數(shù)據(jù)一同改變 |
淺拷貝實(shí)現(xiàn)方式
- Object.assign()
把任意多個(gè)源對(duì)象的可枚舉屬性,拷貝給目標(biāo)對(duì)象案狠,然后返回目標(biāo)對(duì)象服傍。其中拷貝的是對(duì)象屬性的引用,而不是對(duì)象屬性身骂铁。
var obj1= {
age: "12",
language: (3) [1, 2, 3],
name: "a",
love: {son: 'tom'}
};
var obj2=Object.assign({}, obj1); // obj2: {age: "12", language: undefined, name: "a",love: {son: "tom"}}
obj2.love.son='Bob'; // obj2: {age: "12", language: undefined, name: "a",love: {son: "Bob"}}, obj1: {age: "12", language: undefined, name: "a",love: {son: "Bob"}}
// 當(dāng)object 只有一層的時(shí)候吹零,是深拷貝
obj2.age='13' // obj2: {age: "13", language: undefined, name: "a"}, obj1: {age: "12", language: undefined, name: "a"}
- Array.prototype.concat()
修改新對(duì)象的子對(duì)象會(huì)改到原對(duì)象
var arr1=[1,2,{name: 'a1'}];
var arr2=arr1.concat(); // arr2: [1,2,{name: 'a1'}]
arr2[1] = 3; // arr1:[1,2,{name: 'a1'}], arr2: [1,3,{name: 'a1'}]
arr2[2].name='a2'; // arr1:[1,2,{name: 'a2'}], arr2: [1,3,{name: 'a2'}]
- Array.prototype.slice()
修改新對(duì)象的子對(duì)象會(huì)改到原對(duì)象
var arr1=[1,2,{name: 'a1'}];
var arr2=arr1.slice(); // arr2: [1,2,{name: 'a1'}]
arr2[1] = 3; // arr1:[1,2,{name: 'a1'}], arr2: [1,3,{name: 'a1'}]
arr2[2].name='a2'; // arr1:[1,2,{name: 'a2'}], arr2: [1,3,{name: 'a2'}]
深拷貝實(shí)現(xiàn)方式
- JSON.parse(JSON.stringfy())
先轉(zhuǎn)換成JSON字符串再轉(zhuǎn)成JSON對(duì)象,會(huì)產(chǎn)生新的對(duì)象拉庵,而且對(duì)象會(huì)開辟新的棧灿椅,實(shí)現(xiàn)深拷貝。
注意: 不能處理函數(shù),因?yàn)镴SON.stringfy()不能結(jié)束函數(shù)茫蛹,轉(zhuǎn)化結(jié)果為null
var arr = [1, 3, {
username: ' kobe'
}];
var arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].username = 'duncan'; // arr4:[1, 3, {username: 'duncan'}], arr: [1, 3, {username: 'kobe'}]
arr4[1]=2; // arr4:[1, 2, {username: 'duncan'}], arr: [1, 3, {username: 'kobe'}]
- 函數(shù)庫(kù)lodash
_.cloneDeep函數(shù)實(shí)現(xiàn)深拷貝
var obj1={a: 's', {name: 'Lily'}};
var obj2 = _.cloneDeep(obj1);
- 手寫遞歸方法
遍歷對(duì)象操刀,數(shù)組,直到里面都是基本數(shù)據(jù)類型婴洼,再進(jìn)行復(fù)制
function checkedType (target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
function clone (target) {
// result 為最后返回的結(jié)果骨坑, tartgetType為目標(biāo)數(shù)據(jù)類型
let result, tartgetType = checkedType(target)
if (tartgetType === 'Array') {
result = []
} else if (tartgetType === 'Object') {
result = {}
} else {
// 基本數(shù)據(jù)類型,直接返回結(jié)果
return target
}
for (var key in target) {
// 遍歷對(duì)象或數(shù)組窃蹋,直到找到基本數(shù)據(jù)類型進(jìn)行復(fù)制
let value = target[key]
if (checkedType(value) === 'Object' || checkedType(value) === 'Array') {
//繼續(xù)遍歷獲取到value值
result[i] = clone(value)
} else {
result[i] = value
}
}
return result
}