最近在開發中遇到一個小問題,就是由於js的淺拷貝導致變量被污染,突然發現對於js的變量值傳遞和引用傳值並沒有特別注意,如今總結如下,以備來者考慮。
JS的變量分普通類型和引用類型,具體如下:
基本數據類型:String,Boolean,Number,Undefined,Null;
引用數據類型:Object(Array,Date,RegExp,Function);
對於普通類型的變量賦值都是值傳遞,而引用類型變量的賦值。例如下面的代碼:
var b = 3; var c = b; b = 2; console.log(b); // 2 console.log(c); // 3
普通的數據類型變量的賦值,只是值傳遞,變量之間互不影響。而引用類型不同:
var MyObj = { price: "200.00", count: 24 }; var Gift = MyObj; MyObj.price = "300.00"; console.log(Gift.price); // 300.00 console.log(MyObj.price); // 300.00
所以這種引用類型變量的復制是被稱為淺拷貝:新變量的指針指向被復制的變量,當被復制的變量發生變化,新變量也會隨着改變。而我們工作實際中是需要完全拷貝一個變量,一個完整備份,這就是深拷貝。
簡單來說,深淺拷貝的原理圖如下:
所以問題來了,怎么才能實現深拷貝的。
兩種途徑,一種自己使用遞歸的方式去做深拷貝,一種使用第三方庫或者es原生實現。
es6的方式最簡單,結合遞歸代碼如下:
// 遞歸方式實現深拷貝 function DeepCopy(obj) { var return_obj = {}; for (let key in obj) { if (Object.prototype.toString.call(obj[key]) === '[Object Object]') { return_obj[key] = DeepCopy(obj[key]); } else { return_obj[key] = {...obj[key]}; // es6語法糖,處理當前層次賦值為深拷貝 } } return return_obj; }
第三方庫可以使用loadash
var _ = require('lodash'); var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] }; var obj2 = _.cloneDeep(obj1); console.log(obj1.b.f === obj2.b.f); // false