由js深拷貝引起的對內存空間的一些思考
阿新 • • 發佈:2018-03-09
typeof pro 應該 ack RR -c IT init webp
數據類型
js常用數據類型分為基本類型和引用類型
- 基本類型:null、undefined、數值型、字符串型、布爾型
- 引用類型:數組、對象
內存空間
var a = [1, 2, 3]; var b = a; b[2] = 4; a; // ??
我們都知道結果是[1, 2, 4],因為b和a指向了同一個引用對象所以都可以改變該對象的值,我們用內存空間來深入理解一下。
我們知道在內存中存在兩塊區域,一個是棧stack,一個是堆heap。 通常我們的基本數據類型存儲在棧中,而我們的引用數據類型存於堆中。棧中會有一個指針指向存在於堆中的數據以便於引用。
var arr = [1, 2, 3];
內存圖應該是這樣:
arr是一個基本類型的變量,該變量內部存儲著數組的地址/指針,通過該地址可以找到存在於heap中的Array對象。通常我們說arr是一個引用類型我覺得是不嚴謹的,應該說:變量arr指向一個引用類型。
這時候會出現一個問題:允許兩個指針指向同一個堆數據,這意味著通過其中一個指針篡改了數值那麽會影響另一個指針。
var a = [1, 2, 3]; var b = a;
以上變量在內存中的圖是這樣的:
解決該問題的方法就是重新在heap中創建一個與a指向的引用對象一模一樣的對象,然後讓b指向它, 像這樣: 這樣一個b改變了就不會影響a了。
說個題外話:了解這一機制對理解prototype是有很大好處的
function Person(name) { this.name = name; } Person.prototype = { sayHi() { console.log("hi, " + this.name); } }; var p1 = new Person(‘lan‘); p1.sayHi(); // ‘hi, lan‘
內存圖如下,可以自己理解一下,找一找哪些存在於stack哪些存在於heap:
接上述,直接將a賦值為b這樣為淺拷貝,而上上圖中則為深拷貝。
js實現深拷貝思路:
- 先判斷所賦值的類型,如果為基本類型則直接拷貝,若為對象類型則在heap中重新生成一個對象,再遞歸的將值賦值過去。
function deepCopy(obj) { var result = ‘‘; // 為基本類型 if(obj == null || obj == undefined || typeof obj != ‘object‘) return obj; // 為引用類型,判斷為數組還是為對象 if(obj instanceof Array) result = []; else result = {}; for(var key in obj) { var current = obj[key]; if(current == null || current == undefined || typeof current != ‘object‘) result[key] = current; else // 不直接調用deepCopy而用arguments.callee // 以避免函數被賦值給其他變量而出現錯誤 result[key] = arguments.callee(current); } return result; } var a = { name: ‘lan‘, age: 20, birth: [1,2,3,4], like: { food: ‘fruit‘, color: [‘pink‘, ‘blue‘] } }; var b = deepCopy(a); b.birth[2] = 5; a.birth; // [1, 2, 3, 4]
以上為自己對於指針的一點思考,歡迎指正與擴展。
由js深拷貝引起的對內存空間的一些思考