最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一次徹底搞懂JavaScript中的引用賦值、淺拷貝和深拷貝

 更新時間:2025年12月26日 11:08:56   作者:2301_80853669  
在JavaScript編程中拷貝是一個常見的操作,而區(qū)分深拷貝和淺拷貝對于理解程序行為和預(yù)測程序結(jié)果至關(guān)重要,這篇文章主要介紹了JavaScript中引用賦值、淺拷貝和深拷貝的相關(guān)資料,需要的朋友可以參考下

前言

如果你經(jīng)常搞混 深淺拷貝 和 引用賦值,總是記不住它們有什么區(qū)別,在實(shí)際開發(fā)中總是踩坑——比如不小心修改了原始數(shù)據(jù)、或者拷貝不徹底導(dǎo)致奇怪的 bug——那么恭喜你,這篇文章就是為你寫的!我會用最直白的語言、清晰的圖示和大量實(shí)際代碼示例,幫你一次性徹底搞懂!在深入探討拷貝機(jī)制之前,我們需要先了解 JavaScript 的數(shù)據(jù)類型分類和內(nèi)存存儲機(jī)制的基礎(chǔ)概念

一、基礎(chǔ)概念鋪墊

1. JavaScript 數(shù)據(jù)類型分類

  • 基本數(shù)據(jù)類型:字符串(String)、數(shù)字(Number)、布爾(Boolean)、空(Null)、未定義(Undefined)、Symbol、BigInt。
  • 引用數(shù)據(jù)類型:對象(Object)、數(shù)組(Array)、函數(shù)(Function),還有兩個特殊的對象:正則(RegExp)、日期(Date)、正則表達(dá)式、Map、Set、和其他內(nèi)置對象(比如Promise、Error等)

2. 內(nèi)存存儲機(jī)制核心原理

JS 引擎將內(nèi)存劃分為棧內(nèi)存(Stack)堆內(nèi)存(Heap),不同類型的數(shù)據(jù)會被分配到不同的內(nèi)存區(qū)域:嵌套引用依舊遵循下列規(guī)則

特性棧內(nèi)存 (Stack)堆內(nèi)存 (Heap)
存儲內(nèi)容基本數(shù)據(jù)類型值、引用類型的指針引用數(shù)據(jù)類型的實(shí)際內(nèi)容
數(shù)據(jù)結(jié)構(gòu)后進(jìn)先出 (LIFO)動態(tài)分配的樹/圖結(jié)構(gòu)
分配方式連續(xù)內(nèi)存,自動分配隨機(jī)內(nèi)存,動態(tài)分配
訪問速度極快(直接CPU訪問)較慢(通過指針間接訪問)
大小限制?。ㄍǔ?-8MB)大(可達(dá)GB級)
生命周期函數(shù)/塊作用域結(jié)束自動釋放由垃圾回收器(GC)管理

如上圖所示,兩種數(shù)據(jù)類型的內(nèi)存訪問流程如下所示

  • 基本數(shù)據(jù)類型的變量直接從棧內(nèi)存中獲取數(shù)據(jù)
  • 引用數(shù)據(jù)類型的變量訪問過程:
    1. 讀取棧內(nèi)存中的指針(地址)
    2. 通過指針找到堆內(nèi)存中存儲的實(shí)際數(shù)據(jù)

二、不同類型的拷貝行為

1. 基本數(shù)據(jù)類型的拷貝

基本數(shù)據(jù)類型的拷貝非常簡單,由于它們直接存儲在棧內(nèi)存中,拷貝時會直接復(fù)制值本身,不存在引用關(guān)系。

let a = 10;
let b = a; // 直接復(fù)制值
b = 20;
console.log(a); // 10(不受 b 修改影響)
console.log(b); // 20

2. 引用數(shù)據(jù)類型的拷貝

方式一:引用賦值(非拷貝)

引用數(shù)據(jù)類型在賦值時,默認(rèn)是引用賦值(即復(fù)制指針地址),而非復(fù)制實(shí)際內(nèi)容。這意味著兩個變量會指向堆內(nèi)存中的同一個對象。修改其中一個另一個會受影響。

let a = [1, 2, 5];
let b = a; // 引用賦值(復(fù)制指針)
a[1] = 4; // 修改 a 指向的數(shù)組
console.log(a); // [1, 4, 5]
console.log(b); // [1, 4, 5](b 也受影響)
console.log(a === b); // true(指向同一個對象)

方式二: 淺拷貝

淺拷貝是針對引用類型的拷貝方式,它會創(chuàng)建一個新對象,但只復(fù)制對象的第一層屬性。其規(guī)則是:

  • 基本類型屬性:直接復(fù)制值
  • 引用類型屬性:僅復(fù)制指針(不復(fù)制指向的對象本身)

示例1:對數(shù)組 a = [1, 2, [3, 4], 5] 進(jìn)行淺拷貝得到 b 后:

  • b[0]、b[1]、b[3] 是基本類型,修改它們不會影響 a
  • b[2] 是引用類型(數(shù)組),修改 b[2] 會同時影響 a[2],因?yàn)樗鼈冎赶蛲粋€子數(shù)組
const a = [1, 2, [3, 4], 5];
const b = [...a]; // 淺拷貝

a[0] = 100;
console.log(b[0]); // 1(不受影響,基本類型獨(dú)立)

a[2][1] = 400; // 修改子數(shù)組元素
console.log(b[2][1]); // 400(受影響,共享子數(shù)組引用)

示例2:

// 原始對象
const a = {
  name: "alice",  // 基本類型(棧內(nèi)存存儲值)
  profile: {      // 引用類型(堆內(nèi)存存儲對象,棧內(nèi)存存儲指針)
    age: 25,
    city: "beijing"
  }
};

// 使用擴(kuò)展運(yùn)算符進(jìn)行淺拷貝
const b = { ...a };

// 修改淺拷貝對象
b.name = "bob";
b.profile.age = 30;
b.profile.city = "shanghai";

// 查看結(jié)果
console.log("原始對象 a.name:", a.name); 
// 輸出:"alice"(基本類型值獨(dú)立,不受影響)

console.log("原始對象 a.profile.age:", a.profile.age); 
// 輸出:30(引用類型共享堆內(nèi)存,被修改)

console.log("原始對象 a.profile.city:", a.profile.city); 
// 輸出:"shanghai"(引用類型共享堆內(nèi)存,被修改)

console.log("a.profile === b.profile:", a.profile === b.profile); 
// 輸出:true(兩者指向堆中同一個對象)

常見的淺拷貝方法

  1. 擴(kuò)展運(yùn)算符(推薦)
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };
  1. Object.assign()
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);
  1. 數(shù)組的 slice()、concat() 方法
const arr = [1, 2, { a: 3 }];
const shallowCopy1 = arr.slice();
const shallowCopy2 = [].concat(arr);
  1. Array.from()
const arr = [1, 2, { a: 3 }];
const shallowCopy = Array.from(arr);

方式三、深拷貝

深拷貝會創(chuàng)建一個全新的對象,完全復(fù)制原始對象的所有層級屬性,包括嵌套的引用類型,使得新舊對象完全獨(dú)立。

實(shí)現(xiàn)方式 1:JSON 方法(最常用但有局限)

// 原始對象
const a = {
  name: "alice",  // 基本類型(棧內(nèi)存存儲值)
  profile: {      // 引用類型(堆內(nèi)存存儲對象)
    age: 25,
    city: "beijing"
  }
};

// 實(shí)現(xiàn)深拷貝
const deepCopy = JSON.parse(JSON.stringify(a));

// 修改深拷貝對象的屬性
deepCopy.name = "bob"; // 修改基本類型
deepCopy.profile.age = 30; // 修改嵌套引用類型
deepCopy.profile.city = "shanghai";

// 查看結(jié)果對比
console.log("原始對象 a.name:", a.name); 
// 輸出:"alice"(基本類型不受影響)

console.log("原始對象 a.profile.age:", a.profile.age); 
// 輸出:25(嵌套引用類型也不受影響)

console.log("原始對象 a.profile.city:", a.profile.city); 
// 輸出:"beijing"(嵌套引用類型完全獨(dú)立)

console.log("a.profile === deepCopy.profile:", a.profile === deepCopy.profile); 
// 輸出:false(兩者指向堆中不同對象)

注意限制:

  • 無法復(fù)制函數(shù)、undefined、Symbol
  • 日期對象會被轉(zhuǎn)換為字符串
  • 無法處理循環(huán)引用
  • 會丟失原型鏈信息

實(shí)現(xiàn)方式 2:遞歸實(shí)現(xiàn)(自定義深拷貝函數(shù))

由于遞歸實(shí)現(xiàn)較為復(fù)雜,這里不展開詳細(xì)代碼,但基本原理是遍歷對象的所有屬性,對引用類型屬性遞歸調(diào)用拷貝函數(shù),直到所有層級都被復(fù)制。

三、深淺拷貝對比總結(jié)

類型引用類型內(nèi)存地址第一層修改第二層修改
引用賦值引用復(fù)制相同相互影響相互影響
淺拷貝僅第一層值復(fù)制,嵌套層引用復(fù)制不同獨(dú)立相互影響
深拷貝完全復(fù)制不同獨(dú)立獨(dú)立

深淺拷貝的核心區(qū)別在于對嵌套引用類型的處理方式,這直接決定了拷貝后對象的獨(dú)立性:

  • 引用賦值:本質(zhì)上不是拷貝,只是復(fù)制了對象的引用指針。兩個變量共享同一塊堆內(nèi)存,任何層級的修改都會相互影響,內(nèi)存地址相同。
  • 淺拷貝:創(chuàng)建新的內(nèi)存地址存儲對象,但僅對第一層屬性進(jìn)行值復(fù)制。對于基本類型屬性,修改后彼此獨(dú)立;但對于嵌套的引用類型屬性,仍共享原始引用,修改會相互影響。
  • 深拷貝:完全創(chuàng)建新的對象,遞歸復(fù)制所有層級的屬性(包括嵌套引用類型)。新舊對象擁有完全獨(dú)立的內(nèi)存空間,任何層級的修改都不會相互影響,內(nèi)存地址不同。

到此這篇關(guān)于JavaScript中引用賦值、淺拷貝和深拷貝的文章就介紹到這了,更多相關(guān)JS引用賦值、淺拷貝和深拷貝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • js實(shí)現(xiàn)加載頁面就自動觸發(fā)超鏈接的示例

    js實(shí)現(xiàn)加載頁面就自動觸發(fā)超鏈接的示例

    下面小編就為大家?guī)硪黄猨s實(shí)現(xiàn)加載頁面就自動觸發(fā)超鏈接的示例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • js實(shí)現(xiàn)帶緩沖效果的仿QQ面板折疊菜單代碼

    js實(shí)現(xiàn)帶緩沖效果的仿QQ面板折疊菜單代碼

    這篇文章主要介紹了js實(shí)現(xiàn)帶緩沖效果的仿QQ面板折疊菜單代碼,通過JavaScript定時函數(shù)遞歸調(diào)用實(shí)現(xiàn)折疊菜單的緩沖效果,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-09-09
  • 原生js實(shí)現(xiàn)隨機(jī)點(diǎn)名功能

    原生js實(shí)現(xiàn)隨機(jī)點(diǎn)名功能

    這篇文章主要為大家詳細(xì)介紹了原生js實(shí)現(xiàn)隨機(jī)點(diǎn)名功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • 微信小程序—setTimeOut定時器的問題及解決

    微信小程序—setTimeOut定時器的問題及解決

    這篇文章主要介紹了微信小程序—setTimeOut定時器的問題及解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07
  • JavaScript彈出框與事件綁定的超詳細(xì)解析

    JavaScript彈出框與事件綁定的超詳細(xì)解析

    這篇文章主要介紹了JavaScript彈出框與事件綁定的相關(guān)資料,通過示例講解了實(shí)現(xiàn)方式、綜合應(yīng)用及最佳實(shí)踐,如避免內(nèi)存泄漏、優(yōu)化性能、提升用戶體驗(yàn)與可訪問性,需要的朋友可以參考下
    2025-05-05
  • JS實(shí)現(xiàn)仿PS的調(diào)色板效果完整實(shí)例

    JS實(shí)現(xiàn)仿PS的調(diào)色板效果完整實(shí)例

    這篇文章主要介紹了JS實(shí)現(xiàn)仿PS的調(diào)色板效果,結(jié)合完整實(shí)例形式分析了javascript通過運(yùn)算與動態(tài)操作頁面元素實(shí)現(xiàn)調(diào)色板功能的相關(guān)操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-12-12
  • js調(diào)用css屬性寫法

    js調(diào)用css屬性寫法

    對于沒有中劃線的css屬性一般直接使用style.屬性名即可,對于含有中劃線的css屬性,將每個中劃線去掉并將每個中劃線后的第一個字符換成大寫即可,感興趣的朋友可以參考下
    2013-09-09
  • JavaScript中內(nèi)存泄漏的介紹與教程(推薦)

    JavaScript中內(nèi)存泄漏的介紹與教程(推薦)

    內(nèi)存泄露是指一塊被分配的內(nèi)存既不能使用,又不能回收,直到瀏覽器進(jìn)程結(jié)束。下面這篇文章主要給的大家介紹了關(guān)于JavaScript中內(nèi)存泄漏的相關(guān)資料,文中介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • JavaScript實(shí)現(xiàn)鼠標(biāo)經(jīng)過表格某行時此行變色

    JavaScript實(shí)現(xiàn)鼠標(biāo)經(jīng)過表格某行時此行變色

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)鼠標(biāo)經(jīng)過表格某行時此行變色,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • 使用js的replace()方法查找字符示例代碼

    使用js的replace()方法查找字符示例代碼

    JavaScript具有一個非常有用的方法replace(),可以用它利用備選字符集途歡指定的字符,下面有個不錯的示例,大家可以嘗試操作下
    2013-10-10

最新評論

西青区| 兰州市| 达拉特旗| 民乐县| 临清市| 南投市| 大悟县| 榆中县| 綦江县| 江安县| 渭源县| 浦北县| 禹州市| 寿光市| 吉木萨尔县| 古蔺县| 高邮市| 高台县| 枞阳县| 烟台市| 精河县| 黎城县| 文昌市| 资中县| 太仆寺旗| 恩施市| 武宣县| 乐亭县| 进贤县| 夏邑县| 汉川市| 南部县| 塔河县| 浦东新区| 金寨县| 孝昌县| 忻州市| SHOW| 宁安市| 阿拉善左旗| 惠来县|