1. 程式人生 > >物件、陣列傳遞賦值之引用傳遞

物件、陣列傳遞賦值之引用傳遞

開發過程中經常會遇到如下情況,將一個物件賦值給另一個物件,修改後者,前者也隨之改變,場景程式碼如下:

控制檯輸出入下圖:

造成以上現象的原因,個人總結如下:

物件,陣列都是引用型別資料,在上述賦值操作過程中,僅僅是將儲存在棧中的路徑進行的賦值,而未對堆中的資料進行賦值,所以兩者依然依賴相同的堆中儲存的資料,改變後者,實際上是通過棧中儲存的路徑改變了堆中的資料,顧兩者依賴的資料(棧所指向的堆中資料)發生改變,從而影響力前者;

為避免以上場景的發生,我們在開發過程中可通過結構重組或執行方法指令碼(工具函式)等方式將引用傳遞改為值傳遞,具體操作可參考如下程式碼:

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物件;

控制檯輸出如下: