物件、陣列傳遞賦值之引用傳遞
阿新 • • 發佈:2019-02-05
開發過程中經常會遇到如下情況,將一個物件賦值給另一個物件,修改後者,前者也隨之改變,場景程式碼如下:
控制檯輸出入下圖:
造成以上現象的原因,個人總結如下:
物件,陣列都是引用型別資料,在上述賦值操作過程中,僅僅是將儲存在棧中的路徑進行的賦值,而未對堆中的資料進行賦值,所以兩者依然依賴相同的堆中儲存的資料,改變後者,實際上是通過棧中儲存的路徑改變了堆中的資料,顧兩者依賴的資料(棧所指向的堆中資料)發生改變,從而影響力前者;
為避免以上場景的發生,我們在開發過程中可通過結構重組或執行方法指令碼(工具函式)等方式將引用傳遞改為值傳遞,具體操作可參考如下程式碼:
1.對於層級結構簡單的資料可通過結構重組的方式進行深拷貝(值傳遞),demo案例如下:
<script>
var objA = {name:'小明',age:20};
// 通過解構重組的方式賦值
var objB = {...objA};
console.log(objA,objB);
// 改變objB的屬性;
objB.name = '小王';objB.age=18;
console.log(objA,objB);
</script>
控制檯輸出如下:
2.對於層級結構複雜的資料可通過執行方法指令碼(工具函式)的方式進行深拷貝(值傳遞),demo案例如下:
ps:方法程式碼如下:
/* * @method refactor賦值函式 * @param data 資料來源 * @return 處理後的資料 */ function refactor(data){ // 初始化返回資料 let refactorData = null; // 判斷入參是否是陣列 if(Object.prototype.toString.call(data) === '[object Array]'){ // 改變返回資料格式 refactorData = []; // 迴圈入參將資料進一步解析 for(let i=0; i<data.length; i++){ // 判斷子元素是否是物件或陣列 如果是物件或陣列進行方法自呼叫處理資料 if(typeof data[i] ==='object'){ refactorData.push(this.refactor(data[i])); }else{ refactorData.push(data[i]); } } // 判斷入參是否是陣列 }else if(Object.prototype.toString.call(data) === '[object Object]'){ // 改變返回資料格式 refactorData = {}; // 迴圈入參將資料進一步解析 for(let i in data){ // 判斷子元素是否是物件或陣列 如果是物件或陣列進行方法自呼叫處理資料 if(typeof data[i] ==='object'){ refactorData[i] = this.refactor(data[i]); }else{ refactorData[i] = data[i]; } } // 判斷入參是否是其他型別資料 }else{ refactorData = data; } // 返回處理後的資料 return refactorData; }
(1)通過方法進行賦值:
// 執行方法指令碼(工具函式)的方式進行賦值
var objA = [{name:'小明',age:20},[1,2,3,[4,5]],6];
var objB = refactor(objA);
console.log(objA,objB);
(2)輸出結果如下:
(3)改變後者屬性:
// 執行方法指令碼(工具函式)的方式進行賦值 var objA = [{name:'小明',age:20},[1,2,3,[4,5]],6]; var objB = refactor(objA); //改變後者屬性值 objB[0].name = '小王'; objB[1][0] = 0; console.log(objA,objB);
(4)控制檯輸出如圖:
綜合以上demo案例,淺談個人對引用資料賦值的理解,不足之處歡迎指正~
部落格更新:最近接觸了一個前端大佬,接觸到了一個更簡便的資料引用傳遞改為值傳遞的方法,僅需一行程式碼,是的,你沒看錯僅需一行程式碼,並且不需要封裝,案例程式碼如下:
<script>
var objA = {a:[1,2,[3,4]],b:{c:3}};
var objB =JSON.parse(JSON.stringify(objA));
objB.b.c=1;
console.log(objA,objB)
</script>
程式碼解析:先將資料型別轉為字串,再將資料轉換為json物件;
控制檯輸出如下: