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

来源:http://www.cnblogs.com/createGod/archive/2017/08/11/7347296.html
-Advertisement-
Play Games

一、曾經在讀JQ源碼的時候,對深拷貝算是有了一點的理解。我們在項目中是不是經常會遇到這樣的問題呢? 後臺返回一個數組對象(引用類型).次數在頁面渲染中需要對部分數據進行處理 比如:銀行卡62345092534 (這麼長) 但在頁面顯示的時候, 只顯示中國銀行(3118)但是傳給後臺的時候。又要傳62 ...


一、曾經在讀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();

 

四、總結。

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

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • cos是O'Rrilly公司開發的一款用於HTTP上傳文件的OpenSource組件 需要cos.jar,下載地址:http://www.servlets.com/cos/ cos上傳文件很簡單,比fileupload還簡單:但是上傳最大我試了試,是800多兆,超過直接崩潰: java.io.IOE ...
  • UVA - 1629 ans[t][b][l][r]表示t到b行,l到r列那一塊蛋糕切好的最小值d[t][b][l][r]表示t到b行,l到r列區域的櫻桃數,需要預處理 ...
  • 第一步:搭建配置新的虛擬機 格式化之前先把tmp目錄下所有與Hadoop有關的信息全部刪除 rm -rf /tmp/hadoop-centos* 開啟之後jps只有Java的進程:sudo vi /etc/hosts 裡面加 bogon 1.sudo賦權 Root用戶 vi /etc/sudoers ...
  • 前言:這篇博客主要講下這段時間遇到的小問題。比較雜,我自已當作總結了。 真是尷尬,實習之前我是後臺做的比較多,之前花了一個月較系統學了前端html,css,ajax,bootstrap這些,有興趣可以看看我之前寫的前端博客,感覺寫得還可以,對初學者的話。前程明亮-前端系列。學知識嘛,能系統地學習是最 ...
  • 最近一年,在開發實踐過程中遇到了不少問題,大多都能得到解決 部分知其原理,部分只能做到解決問題,而半年前遇到的問題,或多或少都忘得差不多了 是該記錄一下一些問題,防止再遇到就得再查資料了 1. 瀏覽器在開啟有道劃詞插件的時候,使用 AjaxFileUpload 插件上傳文件報錯 開啟插件時,該插件會 ...
  • 可用於製作分頁標簽. 如: 方法一: display: table-cell; 方法二: 定位 示例代碼如下: ...
  • 立即表達式,在javascript中非常常見, 採用立即表達式可以形成一個局部作用域, 常配合閉包實現模塊化編程等其他用途,接下來我們看看,在大多數的框架中,立即表達式都有哪些寫法,以及需要註意的點,另外再介紹下in操作符的用法 1、 通過小括弧把函數聲明變成表達式, 然後再外面加個小括弧 就可以達 ...
  • 剛開始學的時候,對於find()和filter()有點理不清楚,下麵通過案例相信就可以很快的區分清楚 以下是代碼 find彈出的是 filter()彈出的是 下麵我們添加div的class是rain find()彈出結果是 fliter彈出結果是 通過以上案例,我們就清楚的知道,find()是查找某 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...