JavaScript的深拷貝和淺拷貝
原文
簡書原文:https://www.jianshu.com/p/3d930756dd8f
大綱
前言
1、對深拷貝和淺拷貝的初步認識
2、深拷貝和淺拷貝的區別
3、淺拷貝存在的缺陷
4、深拷貝的實現方式
前言
對於很多初次接觸JavaScript的讀者來說,想要實現對象的拷貝/復制,就是單純的使用賦值語句(=)來實現需求。但是,這樣的方式是不全面的,這樣的方法對於簡單類型的數據來說是沒有問題的,但是如果是對於像對象這樣的復雜的數據類型來說,這樣的實現方式有就會給你帶來意想不到的問題。那麽,如果不能簡單的用賦值語句實現對象的拷貝(復制),我們應該用什麽樣的方式呢?這個,就是深拷貝和淺拷貝的意義所在了。
1、對深拷貝和淺拷貝的初步認識
深拷貝和淺拷貝只針對像 Object, Array 這樣的復雜對象的。簡單來說,淺拷貝只拷貝一層對象的屬性,而深拷貝則遞歸拷貝了所有層級。
對於字符串類型,淺拷貝是對值的復制,對於對象來說,淺拷貝是對對象地址的復制,並沒有開辟新的棧,也就是復制的結果是兩個對象指向同一個地址,修改其中一個對象的屬性,則另一個對象的屬性也會改變,而深拷貝則是開辟新的棧,兩個對象對應兩個不同的地址,修改一個對象的屬性,不會改變另一個對象的屬性。
2、深拷貝和淺拷貝的區別
雖然兩者都是對內容的拷貝,但是拷貝的內容的不同是區分兩者的關鍵,而這個不同主要體現在對Object和Array這樣的復雜對象。最直接的原因是諸如字符串這樣簡單的類型的拷貝就是內容的復制,並不會有別的什麽深層次的東西,但是對於Objcet和Array這樣復雜的類型,主要是由於對象的復制是基於對對象的地址的復制而不是整體內容的復制(對象包含了key ,value)。
簡而言之:淺拷貝之後的對象實際上都是同一個對象,而深拷貝之後的對象都是除了內容相同以外完全無關的對象。
3、淺拷貝存在的缺陷
通過一個實例來說明使用淺拷貝對對象進行復制會導致哪些問題,從而正確認識使用深拷貝和淺拷貝的重要意義。
var obj = { a:1, arr: [2,3] }; var shallowObj = shallowCopy(obj); function shallowCopy(src) { var dst = {}; for (var prop in src) { if (src.hasOwnProperty(prop)) { dst[prop] = src[prop]; } } return dst; } /* 導致的結果就是: 對shallowObj對象的更改也會影響到原對象obj,即所謂的牽一發而動全身。 */ shallowObj.arr[1] = 5; obj.arr[1] // = 5
4、深拷貝的實現方式
以下介紹兩種我平時收集到並且常用的深拷貝的實現方式,希望能對讀者有所幫助。
4.1、通過JSON解析解決
針對純 JSON 數據對象的深復制,使用 JSON 全局對象的 parse 和 stringify 方法來實現深復制也算是一個簡單討巧的方法。然而使用這種方法會有一些隱藏的坑,它能正確處理的對象只有 Number, String, Boolean, Array, 扁平對象,即那些能夠被 json 直接表示的數據結構。
var test = { person: { name: { first: ‘chen‘, last: ‘kk‘ }, age: 12 }, interest: [‘book‘, ‘run‘, ‘jump‘] } var result = JSON.parse(JSON.stringify(test)) result.interest.push(‘sing‘) console.dir(test)//[‘book‘, ‘run‘, ‘jump‘] console.dir(result)//friend: [‘book‘, ‘run‘, ‘jump‘,‘sing‘]
4.2、通過遞歸解析解決
想要獲得多層的數據結構的數據的深拷貝,不得不考慮使用叠代的方式。下列的方法將需要考慮深拷貝的對象、Array數據類型,並不斷的通過叠代判斷來對這兩種類型的數據進行深拷貝。
var china = { nation: ‘中國‘, birthplaces: [‘北京‘, ‘上海‘, ‘廣州‘], skincolr: ‘yellow‘, friends: [‘sk‘, ‘ls‘] } //深復制,要想達到深復制就需要用遞歸 function deepCopy(o, c) { var c = c || {} for (var i in o) { if (typeof o[i] === ‘object‘) { //要考慮深復制問題了 if (o[i].constructor === Array) { //這是數組 c[i] = [] } else { //這是對象 c[i] = {} } deepCopy(o[i], c[i]) } else { c[i] = o[i] } } return c } var result = { name: ‘result‘ } result = deepCopy(china, result) console.dir(result)
JavaScript的深拷貝和淺拷貝