1. 程式人生 > >js 中引用類型 的深拷貝 和 淺拷貝的區別

js 中引用類型 的深拷貝 和 淺拷貝的區別

而是 query reac cat 避免 string val this 臨時

一、曾經在讀JQ源碼的時候,對深拷貝算是有了一點的理解。我們在項目中是不是經常會遇到這樣的問題呢?

後臺返回一個數組對象(引用類型).次數在頁面渲染中需要對部分數據進行處理 比如:銀行卡62345092534 (這麽長) 但在頁面顯示的時候,

只顯示中國銀行(3118)但是傳給後臺的時候。又要傳623445242整個號碼,我們也許會把var oldData = res.data;

但是我們發現兩個數據都變了? 這是為什麽呢? 其實就是一個深淺拷貝的問題。

二、淺拷貝

比如數組,對象,這樣的引用類型。

var arr = [‘js‘,‘html‘];
        var oldArr = arr;
        oldArr[
0] = ‘css‘; console.log(arr); // [‘css‘,‘html‘] /* 這其實是一個地址的引用。 相當於他們賦值的是指針。 */ //在數組的方式中可以有兩種方式來避免這種問題 //1.slice var b = [‘vue‘,‘react‘]; var oldB = b.slice(0); b[0] = ‘angular‘; console.log(b); //[‘angular‘,‘react‘] console.log(oldB); //
[‘vue‘,‘react‘] //2.concat(); var c = [‘d3‘,‘three‘,‘webgl‘]; var oldC = c.concat([]); c[0] = ‘earthgL‘; console.log(c,oldC); // "earthgL", "three", "webgl"] ["d3", "three", "webgl"]

對象的淺復制也是一個道理。是對地址的引用而已。

 var obj = {
            name:"前端",
            age:"10"
        }
        
var oldObj = obj; obj.name = "html + css + js"; console.log(oldObj); //{name: "html + css + js", age: "10"}

三、深拷貝。

1.簡單來說 深拷貝就事創建了一個新的內存空間。 他們不在會公用同一個內存空間。是兩個完全獨立的對象或數組。

var defaults = {
  name: ‘quber‘,
  age: [1, 2, 3, 4],
  child: [
   { name: ‘qubernet‘, fun: function () { return 1; } },
   { name: ‘qubernet1‘, fun: function () { return 2; } }
  ]
};
var newDefaults = $.extend(true, {},defaults );
console.log(JSON.stringify(
newDefaults ));

2.JQ深拷貝源碼部分

jQuery.extend = jQuery.fn.extend = function() {

    var options, name, src, copy, copyIsArray, clone,
        target = arguments[0] || {},
        i = 1,
        length = arguments.length,
        deep = false;
    /*
    變量 options:指向某個源對象。
    變量 name:表示某個源對象的某個屬性名。
    變量 src:表示目標對象的某個屬性的原始值。
    變量 copy:表示某個源對象的某個屬性的值。
    變量 copyIsArray:指示變量 copy 是否是數組。
    變量 clone:表示深度復制時原始值的修正值。
    變量 target:指向目標對象,申明時先臨時用第一個參數值。
    變量 i:表示源對象的起始下標,申明時先臨時用第二個參數值。
    變量 length:表示參數的個數,用於修正變量 target。
    變量 deep:指示是否執行深度復制,默認為 false。

    ps:源對象指的是把自己的值付給別人的對象;目標對象指的是被源對象賦值的對象
    */

    // 如果第一個參數傳入的是布爾值
    if ( typeof target === "boolean" ) {
        deep = target;//設置deep變量,確定是深拷貝還是淺拷貝
        target = arguments[1] || {};//將目標對象設為第二個參數值。
        i = 2;//源對象的起始下標設為2(即從第三個參數開始算源對象)
    }

    // Handle case when target is a string or something (possible in deep copy)
    //嗯,原英文解釋的很清楚
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
        target = {};
    }

    // 如果沒有目標對象,那麽目標對象就是jquery對象
    if ( length === i ) {
        target = this;
        --i;
    }

    拷貝的核心部分代碼
    for ( ; i < length; i++ ) {//遍歷源對象
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null ) {//options就是源對象
            // Extend the base object
            for ( name in options ) {//遍歷源對象的屬性名
                src = target[ name ];//獲取目標對象上,屬性名對應的屬性
                copy = options[ name ];//獲取源對象上,屬性名對應的屬性

                // 如果復制值copy 與目標對象target相等,
                //為了避免深度遍歷時死循環,因此不會覆蓋目標對象的同名屬性。
                if ( target === copy ) {
                    continue;
                }

                //遞歸地將源對象上的屬性值合並到目標對象上
                //如果是深拷貝,且待拷貝的對象存在,且是普通對象或是數組
                //這一個判斷條件非常關鍵,這正是之前疑問的癥結
                //首先,普通對象的定義是:通過 "{}" 或者 "new Object" 創建的
                //回到之前的疑問,目標對象tobeCloned的屬性o對象的obj不是普通對象,也不是數組,所以程序不會走到下面的分支
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    if ( copyIsArray ) {
                        //如果是數組
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {
                        clone = src && jQuery.isPlainObject(src) ? src : {};
                    }

                    // 遞歸地拷貝
                    target[ name ] = jQuery.extend( deep, clone, copy );

                } else if ( copy !== undefined ) {
                //會走到這個分支,這個分支的處理很暴力,就是把源對象的屬性,直接賦給源對象。
                //對於上文中tobeCloned對象的屬性o,沒有進一步遞歸地拷貝,而是直接把引用賦給源對象
                //所以改變tobeCloned的o屬性時,目標對象的o屬性也被改變了。
                    target[ name ] = copy;
                }
            }
        }
    }

    // Return the modified object
    return target;
};

3.SE6提供的深拷貝的方法Object.assign();

四、總結。

簡單來說:淺拷貝就是多個變量共用一個地址,深拷貝就是創建了多個內存空間。 (希望對你有幫助)

js 中引用類型 的深拷貝 和 淺拷貝的區別