JavaScript淺拷貝和深拷貝完全解析(別再亂拷貝了!)
前言
在 JavaScript 開發(fā)中,對象拷貝是一個繞不開的核心話題。無論是狀態(tài)管理、數(shù)據(jù)緩存還是函數(shù)參數(shù)傳遞,我們都需要謹慎處理數(shù)據(jù)的復制方式,避免因引用共享導致意外的數(shù)據(jù)修改。
本文將結合實際開發(fā)場景,詳細拆解淺拷貝與深拷貝的區(qū)別、實現(xiàn)方式及適用場景。
一、拷貝的本質:引用 vs 新對象
JavaScript中的對象(包括數(shù)組、函數(shù)等)屬于引用類型,變量存儲時存儲的并非是對象本身,而是對象的引用地址。
- 原始類型拷貝:直接復制值,兩個變量互不影響。
- 引用類型拷貝:如果只是簡單賦值(
const newObj = obj),本質是復制了對象的引用地址,新舊對象指向同一塊內存,修改其中一個會直接影響另一個。
真正的 “拷貝”,是基于原對象創(chuàng)建一個新對象,使新對象與原對象在內存上相互獨立。根據(jù)拷貝的深度,又分為淺拷貝和深拷貝。
二、淺拷貝:只復制第一層
淺拷貝(Shallow Copy)只會復制對象的第一層屬性,如果屬性值是引用類型(如子對象、數(shù)組),則仍然復制其引用地址。
核心特點
- 新對象的第一層屬性與原對象隔離。
- 嵌套的子對象 / 數(shù)組仍共享引用,修改子對象會影響原對象。
常用實現(xiàn)方式
1. 數(shù)組專用方法
Array.prototype.slice(0):創(chuàng)建原數(shù)組的淺拷貝。const arr = [1, 2, { a: 3 }]; const newArr = arr.slice(0); newArr[2].a = 4; // 會修改原數(shù)組的 arr[2].a擴展運算符
...:ES6 新增,語法更簡潔。const newArr = [...arr];
Array.prototype.concat():合并數(shù)組并返回新數(shù)組。const newArr = [].concat(arr);
在一個空數(shù)組后拼接原數(shù)組并賦值給新數(shù)組,這個新數(shù)組就可以說是由原數(shù)組拷貝所得到的。
toReversed()與reverse()方法:
toReversed() 反轉數(shù)組,得到一個新數(shù)組;reverse() 反轉數(shù)組,改變原數(shù)組。通過這兩個方法組合,我們就可以實現(xiàn)淺拷貝的效果。
const newArr=arr.toReversed().reverse()
2. 對象通用方法
Object.assign({}, obj):將原對象的可枚舉屬性復制到新對象。const obj = { a: 1, b: { c: 2 } }; const newObj = Object.assign({}, obj); newObj.b.c = 3; // 原對象 obj.b.c 也會變?yōu)?3Object.assign():是 JavaScript 中用于對象屬性復制與合并的核心方法,它能將一個或多個源對象的可枚舉屬性復制到目標對象中,并返回修改后的目標對象。核心語法
Object.assign(target, ...sources)
target是接受屬性的目標修改對象,...sources是一個或多個提供屬性的對象。
代碼示例:
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
Object.assign(target, source);
console.log(target); // { a: 1, b: 4, c: 5 }
若目標對象與源對象存在同名屬性,后面的源對象屬性會覆蓋前面的。
三、深拷貝:徹底隔離數(shù)據(jù)
深拷貝(Deep Copy)會遞歸復制對象的所有層級,包括嵌套的子對象、數(shù)組等,最終得到一個與原對象完全獨立的新對象,修改新對象不會對原對象產(chǎn)生任何影響。
核心特點
- 新對象與原對象在內存上完全隔離。
- 無論修改哪一層屬性,都不會影響對方。
常用實現(xiàn)方式
1.JSON.parse(JSON.stringify(obj))
這是最常用的 “民間” 深拷貝方案,先將對象序列化為 JSON 字符串,再反序列化為新對象。
const obj = { a: 1, b: { c: 2 } };
const newObj = JSON.parse(JSON.stringify(obj));
newObj.b.c = 3; // 原對象不受影響
局限性:無法處理函數(shù)、Symbol、BigInt、undefined、NaN、Infinity、function 等特殊類型,且會丟失原型鏈。
2.structuredClone()
瀏覽器原生 API,現(xiàn)代瀏覽器和 Node.js 17+ 支持,是更標準的深拷貝方案。
const newObj = structuredClone(obj);
局限性:無法拷貝函數(shù)、Symbol,也不能處理帶有循環(huán)引用的對象。
四、總結
- 淺拷貝:高效、輕量,適合處理扁平結構數(shù)據(jù),但要注意嵌套引用的問題。
- 深拷貝:徹底隔離數(shù)據(jù),避免副作用,但性能開銷更大。
- 核心原則:根據(jù)數(shù)據(jù)結構和業(yè)務場景選擇合適的拷貝方式,避免過度設計。
在實際開發(fā)中,我們應優(yōu)先使用淺拷貝保證性能,只有在數(shù)據(jù)結構復雜且需要完全隔離時,才考慮深拷貝。理解拷貝的本質,是寫出健壯、可維護的 JavaScript 代碼的關鍵一步。
到此這篇關于JavaScript淺拷貝和深拷貝完全解析的文章就介紹到這了,更多相關JS淺拷貝和深拷貝內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解JavaScript對數(shù)組操作(添加/刪除/截取/排序/倒序)
這篇文章主要介紹了JavaScript對數(shù)組操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04
JavaScript獲取flash對象與網(wǎng)上的有所不同
關于js獲取flash對象,網(wǎng)上有非常多的例子,但不是我想要的,經(jīng)測試整理,因此本文誕生了2014-04-04
兩個JavaScript中的特殊值null和undefined詳解
Null和Undefined是JavaScript中非?;A和重要的概念,理解它們的含義、特點和使用方式對于避免出現(xiàn)錯誤和編寫健壯的應用程序非常重要,這篇文章主要介紹了兩個JavaScript中的特殊值null和undefined詳解,需要的朋友可以參考下2023-06-06

