Javascript/js 的淺拷貝與深拷貝(複製)學習隨筆

来源:https://www.cnblogs.com/caimuguodexiaohongmao/archive/2019/06/29/11108217.html
-Advertisement-
Play Games

js變數的數據類型值分基本類型值和引用類型值。 在ES6(ECMAScript6)以前,基本數據類型包括String、Number、Boolean、Undefined、Null。 基本類型值的複製(拷貝) 從一個變數向另一個變數複製基本類型的值。使用賦值操作符 ' = ' 即可。 如: 上述代碼定義 ...


js變數的數據類型值分基本類型值和引用類型值。

在ES6(ECMAScript6)以前,基本數據類型包括String、Number、Boolean、Undefined、Null。

基本類型值的複製(拷貝)

從一個變數向另一個變數複製基本類型的值。使用賦值操作符 ' = ' 即可。

如: 

1 var num1 = 1, num2;
2 num2 = num1;

上述代碼定義了兩個變數num1、num2。num1初始化值是1,num2是undefined。接著把num1賦值給num2。

num1的值與num2的值增刪改減完全獨立、互不影響。

1 ++num1;
2 num2 = null;
3 // 2 null

拓展:基於基本類型值,ES提供了三個特殊的引用類型。String、Number、Boolean。(基本包裝類型)

1 var num3 = 3;
2 var num4 = num3.toFixed(2);
3 console.log(num3, num4); // 3 3.00

如上,變數num3包含一個數字值,數字當然屬於基本類型值啦,接著num3調用了toFixed()方法。並將返回結果保存在num4中。最後在控制台輸出下。結果是3 3.00。當然了,沒有報錯。。

一般來理解,基本類型值不是對象,不應該有方法。(但是它們確實有方法.。查看它們有哪些方法的一個辦法是在chrome控制台console.log(new Number(1))。其他基本類型值同理。baidu/翻書/強記。do whatever you want)

當第二行代碼訪問num3時,訪問過程處於一種讀取模式,也就是從記憶體中讀取這個變數的值。此時,在後臺,大概是執行了下列的es代碼:

1 var _num3 = new Number(3);// 創建Number類型的一個實例
2 var _num4 = _num3.toFixed(2);// 在實例上調用指定的方法
3 _num3 = null;// 銷毀這個實例
4 return _num4;// 可以想象成在一個函數里執行這裡的4行代碼,函數返回_num4。接著被num4接收。

這也意味著我們可以對基本類型值做一些擴展。比如:

1 var num5 = 1;
2 Number.prototype.addTen = function () {
3   var res = this + 10;
4   return res;
5 };
6 console.log(num5.addTen());// 11    

如上,在Number原型上定義addTen()方法,所有Number類型值都可以調用這個方法。

其他基本類型值同理。

ES6規範引入了一項新特性--symbol,它也是一種基本數據類型,它的功能類似於一種標識唯一性的ID。

調用Symbol函數來創建一個Symbol實例:

1 const S1 = Symbol();
2 // 可以在調用Symbol函數時傳入一個參數,相當於給你創建的Symbol實例一個描述信息。參數可選,可以是任意可轉化成字元串的值。
3 const S2 = Symbol('id9527');

引用類型的複製(拷貝)

常見的引用類型包括 Object、Aarry、Date、Function、RegExp...

引用類型值是引用類型的一個實例。

通過賦值操作符‘=’複製的引用類型值。實際上複製的是一個指針(地址)。該指針指向存儲在堆中的對象。

1 const obj1 = new Object();
2 const obj2 = obj1;
3 obj1.name = 'xm';
4 console.log(obj2.name);// xm

obj1與obj2指向同一個對象,對obj1的修改,同樣作用於obj2。

多數時候這不是我們想要的結果。我們需要的是兩個相互獨立而又長得一模一樣的對象。

由於引用類型值也可能包含引用類型值。由此就派生出了淺拷貝和深拷貝。

淺拷貝

數組的淺拷貝常用方法:

(1)concat方法

1 const arr1 = ['a', 'b', ['c', 4]];
2 const arr2 = arr1.concat([]);
3 console.log(arr2, arr1 == arr2);// ['a', 'b', ['c', 4]] false

(2)slice方法

1 const arr1 = ['a', 'b', ['c', 4]];
2 const arr2 = arr1.slice(0);
3 console.log(arr2, arr1 == arr2);// ['a', 'b', ['c', 4]] false

(3)擴展運算符...方法

1 const arr1 = ['a', 'b', ['c', 4]];
2 const arr2 = [...arr1];
3 // const [...arr2] = arr1; // 等同於上一行
4 console.log(arr2, arr1 == arr2);// ['a', 'b', ['c', 4]] false

(4)map方法

1 const arr1 = ['a', 'b', ['c', 4]];
2 const arr2 = arr1.map(item => item);
3 console.log(arr2, arr1 == arr2);// ['a', 'b', ['c', 4]] false

(5)filter方法 把上面的map改成filter即可。

...for迴圈、forEach、for of、splice、Object.values等方法均可。

對象的淺拷貝常用方法:

1、for in遍歷方法

 1 const obj = {
 2   say(){
 3     console.log('hello');
 4   }
 5 };
 6 const obj1 = Object.create(obj);
 7 obj1.a = '對象';
 8 obj1.b = [1, 2, 3];
 9 
10 // const obj2 = Object.create(obj); // 繼承obj的屬性、方法
11 const obj2 = {};
12 for (let p in obj1) {
13   if (obj1.hasOwnProperty(p)) {
14     obj2[p] = obj1[p];
15   }
16 }

如上,obj1的原型對象是obj,淺拷貝一般不需要拷貝原型上的屬性和方法,而for in迴圈可以枚舉原型上的屬性和方法。使用hasOwnProperty()方法過濾掉原型的屬性和方法。

結果如下:

(2)Object.entries()方法

 1 const obj = {
 2   say(){
 3     console.log('hello');
 4   }
 5 };
 6 
 7 const obj1 = Object.create(obj);
 8 obj1.a = '對象';
 9 obj1.b = [1, 2, 3];
10 
11 // const obj2 = Object.create(obj); // 繼承obj的屬性、方法
12 const obj2 = {};
13 Object.entries(obj1).forEach(([key, value]) => obj2[key] = value);
結果如下:

 之所以稱為淺拷貝,其原因在於如果引用類型值里包含引用類型值,上述的所有方法,在對裡層的引用類型值複製操作時,使用的還是賦值操作符'='。如下所示:

如果修改了obj1.b的值,同樣會作用於obj2。

深拷貝

以下是實現對數組、對象深拷貝的一種方法。

採用遞歸的方式,層層遍歷。

 1 const deepClone = function handleDeepClone(obj) {
 2   if (typeof obj !== 'object' || obj === null) {
 3     return obj;
 4   }
 5 
 6   let _obj;
 7   if (obj instanceof Array) {
 8     _obj = [];
 9     obj.forEach((item, i) => _obj[i] = handleDeepClone(item));
10   } else {
11     _obj = {};
12     Object.entries(obj).map(([key, value]) => _obj[key] = handleDeepClone(value));
13   }
14 
15   return _obj;
16 };

 結果如下:

 


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

-Advertisement-
Play Games
更多相關文章
  • 資料庫是數據存儲的最外層(最大單元) 1、創建資料庫 基本語法:create database 資料庫名字 [庫選項]; 範例:使用create database 創建資料庫 庫選項:資料庫的相關屬性 字元集:charset 字元集,代表著當前資料庫下的所有表存儲的數據預設指定的字元集(如果當前不指 ...
  • 一、DQL 1、基本規則: (1)對於日期型數據,做 *,/ 運算不合法,可以進行 +, - 運算。比如給日期加一天或減一個月,結果仍為一個日期。兩個日期間只能為減法,返回兩個日期相差的天數,兩個日期間做加法沒任何意義。 (2)包含空值(null)的數學表達式計算結果均為空值。 (3)給欄位取別名時 ...
  • 一、DDL 1、創建表(CREATE) (1)資料庫對大小寫不敏感,只對字元串大小寫敏感。 (2)使用create關鍵字創建表。(-- 表示註釋)。 (3)將一個查詢結果集作為一張表。可用於將多張表連成一張表的操作。 2、刪除表(DROP)、DESC關鍵字、TRUNCATE關鍵字 (1)使用DESC ...
  • 之前用python連過mysql資料庫,但是沒連過oracle資料庫,所以來練習一波 ...
  • --查看當前鏈接情況: select * from sys.servers; --使用 sp_helpserver 來顯示可用的伺服器 Exec sp_helpserver --刪除已經存在的某個鏈接 Exec sp_droplinkedsrvlogin 伺服器別名,NullExec sp_drop ...
  • 資料庫概念 資料庫(Database)是按照數據結構來組織、存儲和管理數據的建立在電腦存儲設備上的倉庫。 資料庫:存儲數據的倉庫 資料庫分類 網路資料庫 網路資料庫是指把資料庫技術引入到電腦網路系統中,藉助於網路技術將存儲於資料庫中的大量信息及時發佈出去;而電腦網路藉助於成熟的資料庫技術對網路 ...
  • 在網上找來段使用jQuery火箭圖標返回頂部代碼,感覺比較酷,比較炫,大概樣式如下, 很酷炫哦! 如果第一次自定義博客園,需要申請許可權 點擊博客園的【管理】 → 【設置】→ 一直往下拉, 找到【博客側邊欄公告(支持HTML代碼)(申請JS許可權)】 向[email protected] 發送郵件, ...
  • 哈嘍,我開始有自己的博客了! 既然這樣,以後我將不定時在這裡分享乾貨啦! 當然,今天也不是空著手來的~ 附上一個用於Web前端的input組件的郵件約束呢 希望喜歡的朋友,要跟緊我哦 發佈時間:2019-06-29 23:19:11 html源代碼 效果圖 /******************** ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...