標籤:數值 asc 通過 hal school string tail 字串 ons
文章目錄
- JavaScript中的變數類型
- 深拷貝和淺拷貝的理解
- 深拷貝和淺拷貝的實現方式
- 為什麼需要深拷貝和淺拷貝
JavaScript中的變數類型
(1)、基本類型
JavaScript中的基本類型有五種: null、undefined、boolean、string、number。 變數是按值存放的,存放在棧中的簡單資料區段,可以直接存取。
(2)、參考型別
參考型別包括對象和數組,其儲存在堆當中,而變數是指標,指向堆。 當我們訪問的時候,實際上是訪問指標,然後指標去尋找對象或數組。
深拷貝與淺拷貝的理解
(1)、深拷貝
先建立一個Null 物件,記憶體中新開闢一塊地址,把被複製對象的所有可枚舉的(注意可枚舉的對象)屬性方法一一複製過來,注意要用遞迴來複製子物件裡面的所有屬性和方法,直到子子.....屬性為基礎資料型別 (Elementary Data Type)。關鍵點:開闢新記憶體、遞迴複製。
另外一種定義:深拷貝指的是對象屬性所引用的對象全部進行建立對象複製,以保證深複製的對象的引用圖不包含任何原有對象或對象圖上的任何對象,隔離出兩個完全不同的對象圖。
(2)、淺拷貝
一個對象複製另外一個對象,如果不是深拷貝,就是淺拷貝。 簡單地說,淺拷貝就是將一個對象的記憶體位址的“”編號“”複製給另一個對象。即在真正訪問的時候還是會訪問到被複製對象。 或者只是深拷貝了第一層的參考型別,而沒有拷貝更深層次的應用類型,而是利用複製地址的方式,這也是淺拷貝。
深拷貝和淺拷貝的實現方式 淺拷貝淺拷貝1
var obj1 = { name: ‘wayne‘ } var obj2 = obj1 obj2.name = ‘hedy‘ console.log(obj1.name) // ‘hedy‘
這裡首先建立了一個 obj1 對象,然後將obj複製給了 obj2, 但是這裡僅僅是指標的複製,所以在修改 obj2.name 的時候,實際上是修改的同一個堆中的對象,既淺拷貝。
淺拷貝2
var obj = { a: 1, b: { d: { e: ‘test‘ } }, c: [1, 2, 3] } function shallowClone1(copyObj) { var newObj = {}; for (var prop in copyObj) { newObj[prop] = copyObj[prop]; } return newObj; } var newObj = shallowClone1(obj); console.log(newObj.b.d === obj.b.d); // true
即通過for in的形式將對象進行複製,這裡可以看到複製只是對於指標的複製,得到的新的對象還是指向同一個堆中的對象,所以是淺複製。
淺拷貝3
Object.assign()
var obj1 = { name: ‘wayne‘, age: 22, other: { hobby: ‘table‘, school: ‘xjtu‘ } } var obj2 = Object.assign({}, obj1); obj2.name = ‘hedy‘ console.log(obj1.name) // wayne obj2.other.hobby = ‘sing‘ console.log(obj1.other.hobby) // sing
只從表面上來看,似乎Object.assign()的目標對象是{},是一個新的對象(開闢了一塊新的記憶體空間),是深拷貝。
當我們修改obj2.name的時候,obj1.name沒有改變,但是當我們修改 obj2.other.hobby 的時候,obj1.other.hobby 同樣也發生了變化。
即Object.assign()也是淺拷貝,或者說只是深拷貝了第一層,這樣我們認為它還是淺拷貝。
淺拷貝4
concat
var a = [2, [3,5,7], {name: ‘wayne‘}]; var b = a.concat(4) a[0] = 3; console.log(b[0]) // 2 看起來像深複製 a[1][0] = 666; console.log(b[1][0]) // 666 淺複製 a[2].name = ‘hedy‘ console.log(b[2].name) // hedy 淺複製
可以看到通過concat返回的新數組,只有改變其中一個的布爾值、字串、數值,另一個不會改變,但是改變其中的對象、數組時,可以發現,另一個也在同時改變,即還是引用原來的堆中的內容。
slice
var a = [2, [3,5,7], {name: ‘wayne‘}]; var b = a.slice(0) a[0] = 3; console.log(b[0]) // 2 看起來像深複製 a[1][0] = 666; console.log(b[1][0]) // 666 淺複製 a[2].name = ‘hedy‘ console.log(b[2].name) // hedy 淺複製
這段代碼僅僅是將上一段中的concat修改為了slice,發現結果也是一樣的,即slice方法得到的也是淺複製。
深拷貝
深拷貝1
JSON.stringify() 和 JSON.parse()
var obj1 = { name: ‘wayne‘, age: 22, other: { hobby: ‘table‘, school: ‘xjtu‘ } } var obj2 = JSON.parse(JSON.stringify(obj1)); obj2.name = ‘hedy‘ console.log(obj1.name) // wayne obj2.other.hobby = ‘sing‘ console.log(obj1.other.hobby) // table
可以看出通過JSON.stringify先將對象轉化為字元換,然後再通過JSON.parse()轉化為對象,這個對象就是完全在開闢的新的記憶體空間中的對象 。
深拷貝2
jquery $.clone(true) / $.extend(true)
var x = { a: 1, b: { f: { g: 1 } }, c: [ 1, 2, 3 ] }; var y = $.extend({}, x), //淺複製 z = $.extend(true, {}, x); //深複製 console.log(y.b.f === x.b.f ) // true console.log(z.b.f === x.b.f) // false
可以看到通過 $.extend() 傳入第一個參數 true, 就可以進行深複製了。
推薦文章:https://www.zhihu.com/question/23031215
http://blog.csdn.net/waiterwaiter/article/details/50267787
Javascript中的深拷貝和淺拷貝