一文帶你了解JavaScript基礎(chǔ)之深拷貝和淺拷貝
拷貝(又名克隆,復(fù)制等),但是又分深拷貝和錢拷貝。
其實(shí)這個(gè)問題有時(shí)候想通了就很簡單,如果想不通可能會有點(diǎn)繞,不過其難度比閉包等好理解的多。
為什么又這個(gè)概念的存在呢?先舉一個(gè)例子。
var person={
name:"張三",
age:22
}
var person1=person;
console.log(person);
console.log(person1);

似乎可以被拷貝下來了,但是如果你操作person1的屬性值,這個(gè)時(shí)候person屬性值也會改變。
person1.name="李四"; console.log(person); console.log(person1);

其實(shí)這個(gè)很容易理解,那就是上面只是兩個(gè)對象的指針地址都是指向棧內(nèi)存的相同位置,前面講解引用數(shù)據(jù)類型的時(shí)候講解過何為引用數(shù)據(jù)類型。
補(bǔ)充 :
對象.屬性 和對象[屬性]其實(shí)都是操作對象的屬性值,只是兩個(gè)不同的寫法而已。
那說明這種指針賦值的方式不是拷貝,那什么就是拷貝呢,那就是一個(gè)新的對象用用了一個(gè)對象的所有屬性,但彼此不受影響。
這樣的理解就明白了,拷貝的本質(zhì)就是將一個(gè)對象的屬性循環(huán)賦值給一個(gè)新的對象而已。
那有為什么分淺拷貝和深拷貝,說實(shí)話淺拷貝和深拷貝本質(zhì)上有什么什么區(qū)別嗎?
其實(shí)本質(zhì)沒有區(qū)別,最大的區(qū)別就是考慮的條件以及拷貝過程中的屬性類型不同而已。
老規(guī)矩先看代碼
淺拷貝
var person={
name:"張三",
age:22
}
var person1={};
for( key in person){
console.log(key);
person1[key]=person[key];
}
console.log(person);
console.log(person1);

person1.name="李四"; console.log(person); console.log(person1);

可以看出沒有彼此影響,但是又會涉及到新的問題,那就是person對象的屬性都是基本數(shù)據(jù)類型,如果是引用類型呢?比如數(shù)組,對象呢?
var person={
name:"張三",
age:22,
son:{
firstSon:"張大毛"
}
}
var person1={};
for( key in person){
console.log(key);
person1[key]=person[key];
}
console.log(person);
console.log(person1);

現(xiàn)在修改一下person1的送屬性。
person1.son={firstSon:"李大毛"};
console.log(person);
console.log(person1);

這樣看似乎也沒有彼此影響嗎?但是這個(gè)前面說過對象.屬性=這樣等于重寫賦值了person1.son的屬性,自然會斷開引用彼此的影響,畢竟兩個(gè)地址不一樣。但是如下修改呢?
person1.son.secondeSon="李大毛"; console.log(person); console.log(person1);

驚不驚喜,意不意外還是彼此影響了,這個(gè)時(shí)候就需要一種新的操作了那就是深拷貝,說白了就是將屬性值的有可能會為用引用類型。
補(bǔ)充:
如果person的原型上有屬性值,也會被person1取到,賦值給person1.這個(gè)前面說到過,那樣的話就會用到hasOwnProperty這個(gè)來判斷是否屬于自己的屬性值。
深拷貝
其實(shí)深拷貝和淺拷貝的區(qū)別,相信看到這里幾乎已經(jīng)明白了差不多了,就是考慮屬性值的類型而已。
// 上面補(bǔ)充了說了原型上的值也會被拷貝下來,為了方便直接用對象的原型鏈最后Object添加屬性。
Object.prototype.address="你猜";
var person={
name:"張三",
age:22,
son:{
firstSon:"張大毛"
}
}
strtype=Object.prototype.toString;
var person1={};
// 為了方便這個(gè)地方用遞歸方法
function coleFun(origin,target){
// 防止目標(biāo)對象本身有屬性
target=target||{}
for( key in origin){
if(origin.hasOwnProperty(key))
if(strtype.call(origin[key])=="[object Object]"){
target[key]={};
target[key]=coleFun(origin[key],target[key])
}else{
target[key]=origin[key];
}
}
return target;
}
person1=coleFun(person,person1)
console.log(person);
console.log(person1);

看結(jié)果沒有問題 現(xiàn)象修改一下屬性值試試
person1.son.secondeSon="李大毛"; console.log(person); console.log(person1);

現(xiàn)在看沒有問題。
所謂的深淺拷貝,說白了就是考慮屬性值是否會有引用類型,然后在進(jìn)行拷貝而已。如果上面代碼沒有看懂的話,可能需要重溫一下引用數(shù)據(jù)和基本數(shù)據(jù)的區(qū)別,以及this指向,還有數(shù)據(jù)類型的判斷方法。這寫前面的文章都有聊過,可以翻看一下。
補(bǔ)充
有個(gè)朋友在評論區(qū)說如果如果用JavaScript中的JSON的方法進(jìn)行拷貝數(shù)據(jù),是深拷貝還是淺拷貝?
其實(shí)這個(gè)很容易證明的,那就是直接拷貝一個(gè)帶有引用數(shù)據(jù)類型的對象,然后判斷其是否會彼此影響即可。
首先看一下其含有的兩種方法以及作用:
| 方法 | 作用 |
|---|---|
JSON.parse() |
用于將一個(gè)JSON字符串轉(zhuǎn)換為 JavaScript 對象。 |
JSON.stringify() |
用于將 JavaScript 值轉(zhuǎn)換為JSON字符串。 |
然后代碼演示:
var person={
name:"張三",
age:22,
son:{
firstSon:"張大毛"
}
}
var str=JSON.stringify(person);
var person1=JSON.parse(str);
console.log(person);
console.log(person1);

拷貝的目前看結(jié)果至少沒有問題。
現(xiàn)在開始測試,是否相互影響
person1.son.secondeSon="李大毛"; console.log(person); console.log(person1);

可見沒有相互影響,其是通過JOSN進(jìn)行拷貝其實(shí)是JavaScript一種常見的方式,畢竟比自己寫要方便的很多。其本質(zhì)就是將對象轉(zhuǎn)成一個(gè)JSON格式的字符串,而通過字符串再生成一個(gè)對象而已,所以說其也是一種深拷貝。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
javascript獲取函數(shù)名稱、函數(shù)參數(shù)、對象屬性名稱的代碼實(shí)例
這篇文章主要介紹了javascript獲取函數(shù)名稱、函數(shù)參數(shù)、對象屬性的代碼實(shí)例,需要的朋友可以參考下2014-04-04
Javascript入門學(xué)習(xí)第五篇 js函數(shù)
上篇文章講了js中對象和數(shù)組的一些方法。 這章我們先說說函數(shù),然后來點(diǎn)實(shí)戰(zhàn)。2008-07-07
5個(gè)最頂級jQuery圖表類庫插件【jquery插件庫】
這篇文章主要介紹了5個(gè)最頂級jQuery圖表類庫插件【jquery插件庫】,需要的朋友可以參考下2016-05-05
每個(gè)程序員都需要學(xué)習(xí) JavaScript 的7個(gè)理由小結(jié)
這篇文章主要介紹了每個(gè)程序員都需要學(xué)習(xí) JavaScript 的7個(gè)理由小結(jié),需要的朋友可以參考下2016-09-09
JavaScript學(xué)習(xí)筆記之Cookie對象
本文主要簡單介紹了javascript中cookie對象的概念,以及cookie的讀取,寫入,刪除操作的方法,并附上示例,非常不錯(cuò),這里推薦給小伙伴們。2015-01-01

