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

一文徹底搞懂JS數(shù)據(jù)類(lèi)型之基本類(lèi)型與引用類(lèi)型的核心差異

 更新時(shí)間:2026年03月09日 09:24:40   作者:奔跑的web.  
在javascript中,引用數(shù)據(jù)類(lèi)型是一種數(shù)據(jù)結(jié)構(gòu),用于將數(shù)據(jù)和功能組織在一起,它也常被稱(chēng)為類(lèi),這篇文章主要介紹了JS數(shù)據(jù)類(lèi)型之基本類(lèi)型與引用類(lèi)型核心差異的相關(guān)資料,需要的朋友可以參考下

前言

在 JavaScript 開(kāi)發(fā)中,遇到過(guò)這樣的困惑:同樣是變量賦值,為什么修改一個(gè)變量,有的時(shí)候另一個(gè)變量不受影響,有的時(shí)候卻會(huì)跟著變?其實(shí)這背后的核心原因,就在于 JavaScript 中兩種數(shù)據(jù)類(lèi)型——基本數(shù)據(jù)類(lèi)型引用數(shù)據(jù)類(lèi)型的不同存儲(chǔ)與賦值機(jī)制。

這是 JS 中的基礎(chǔ)核心知識(shí)點(diǎn),也是理解后續(xù)原型鏈、閉包、深淺拷貝等概念的前提。本文將從存儲(chǔ)本質(zhì)、賦值行為、修改影響等維度,結(jié)合大量實(shí)例,徹底理清兩者的差異,從此告別數(shù)據(jù)類(lèi)型相關(guān)的“坑”。

一、先明確:JS 中的兩種數(shù)據(jù)類(lèi)型分類(lèi)

JavaScript 中的數(shù)據(jù)類(lèi)型分為兩大類(lèi),這是 ES6 標(biāo)準(zhǔn)明確規(guī)定的,我們先清晰劃分:

  • 基本數(shù)據(jù)類(lèi)型(Primitive Types) :也叫原始類(lèi)型,是不可再分的基本值。包括:Number、String、Booleannull、undefinedSymbol(ES6 新增)、BigInt(ES10 新增)。
  • 引用數(shù)據(jù)類(lèi)型(Reference Types) :也叫復(fù)雜類(lèi)型,是由多個(gè)基本類(lèi)型或其他引用類(lèi)型組合而成的結(jié)構(gòu)。包括:ObjectArray、Function、DateRegExp 等所有非基本類(lèi)型。

兩者最核心的區(qū)別,在于在內(nèi)存中的存儲(chǔ)方式不同——這直接決定了它們的賦值行為和修改影響。

二、核心差異一:內(nèi)存存儲(chǔ)方式不同

JavaScript 運(yùn)行時(shí),內(nèi)存主要分為兩個(gè)區(qū)域:棧內(nèi)存(Stack)堆內(nèi)存(Heap) 。兩種數(shù)據(jù)類(lèi)型分別存儲(chǔ)在這兩個(gè)區(qū)域,這是所有差異的根源。

2.1 基本數(shù)據(jù)類(lèi)型:直接存儲(chǔ)在棧內(nèi)存

基本數(shù)據(jù)類(lèi)型的特點(diǎn)是“體積小、結(jié)構(gòu)簡(jiǎn)單”,所以 JS 引擎會(huì)直接把它們的值存儲(chǔ)在棧內(nèi)存中。變量名直接指向棧內(nèi)存中的具體值,不存在“引用”的概念。

我們用一個(gè)簡(jiǎn)單的示意圖理解:

變量 x → 棧內(nèi)存 → 值:30

舉個(gè)代碼示例:

// 基本數(shù)據(jù)類(lèi)型:Number
var x = 30;
// 變量 y 賦值為 x 的值
var y = x;

此時(shí)內(nèi)存中的狀態(tài)是:棧內(nèi)存中會(huì)創(chuàng)建兩個(gè)獨(dú)立的空間,分別存儲(chǔ) 30(對(duì)應(yīng) x)和 30(對(duì)應(yīng) y)。x 和 y 各自指向自己的棧內(nèi)存空間,互不干擾。

2.2 引用數(shù)據(jù)類(lèi)型:值存儲(chǔ)在堆內(nèi)存,引用存儲(chǔ)在棧內(nèi)存

引用數(shù)據(jù)類(lèi)型的特點(diǎn)是“體積大、結(jié)構(gòu)復(fù)雜”(比如一個(gè)包含多個(gè)屬性的對(duì)象、一個(gè)長(zhǎng)度很長(zhǎng)的數(shù)組)。如果把它們直接存儲(chǔ)在棧內(nèi)存,會(huì)導(dǎo)致棧內(nèi)存占用過(guò)大,影響程序運(yùn)行效率。

因此 JS 引擎采用了“分離存儲(chǔ)”的策略:

  • 把引用類(lèi)型的實(shí)際值存儲(chǔ)在堆內(nèi)存中;
  • 把堆內(nèi)存中該值的內(nèi)存地址(引用) 存儲(chǔ)在棧內(nèi)存中;
  • 變量名指向棧內(nèi)存中的“引用地址”,通過(guò)這個(gè)地址才能找到堆內(nèi)存中的實(shí)際值。

示意圖理解:

變量 x → 棧內(nèi)存 → 引用地址:0x123 → 堆內(nèi)存 → 實(shí)際值:{ m: 1 }

代碼示例:

// 引用數(shù)據(jù)類(lèi)型:Object
var x = { m: 1 };
// 變量 y 賦值為 x 的引用地址
var y = x;

此時(shí)內(nèi)存中的狀態(tài)是:堆內(nèi)存中創(chuàng)建一個(gè)空間存儲(chǔ)對(duì)象 { m: 1 },棧內(nèi)存中 x 和 y 存儲(chǔ)的都是同一個(gè)引用地址(比如 0x123),這個(gè)地址都指向堆內(nèi)存中的同一個(gè)對(duì)象。

三、核心差異二:賦值行為與修改影響不同

基于不同的存儲(chǔ)方式,兩種數(shù)據(jù)類(lèi)型的賦值操作和修改操作,會(huì)產(chǎn)生完全不同的結(jié)果。這也是開(kāi)發(fā)中最容易遇到“坑”的地方。

3.1 基本數(shù)據(jù)類(lèi)型:賦值是“值的復(fù)制”,變量間互相獨(dú)立

基本數(shù)據(jù)類(lèi)型的賦值,本質(zhì)是把棧內(nèi)存中的“實(shí)際值”復(fù)制一份,賦值給新的變量。復(fù)制完成后,兩個(gè)變量擁有各自獨(dú)立的值,修改其中一個(gè),絕對(duì)不會(huì)影響另一個(gè)。

// 基本數(shù)據(jù)類(lèi)型:Number
var x = 30;
// 賦值:把 x 的值 30 復(fù)制給 y
var y = x;

// 修改 x 的值
x += 10; // x 變成 40

// 查看 y 的值:不受影響
console.log(y); // 輸出 30

再看一個(gè) String 類(lèi)型的例子,結(jié)果一致:

var str1 = "hello";
var str2 = str1;

str1 = str1 + " world"; // str1 變成 "hello world"
console.log(str2); // 輸出 "hello",不受影響

這里要注意:雖然 JS 中的 String 是不可變的(無(wú)法直接修改字符串的某一位),但賦值行為依然遵循基本類(lèi)型的“值復(fù)制”規(guī)則,變量間互相獨(dú)立。

3.2 引用數(shù)據(jù)類(lèi)型:賦值是“引用的復(fù)制”,變量間指向同一對(duì)象

引用數(shù)據(jù)類(lèi)型的賦值,本質(zhì)是把棧內(nèi)存中的“引用地址”復(fù)制一份,賦值給新的變量。復(fù)制完成后,兩個(gè)變量擁有同一個(gè)引用地址,都指向堆內(nèi)存中的同一個(gè)對(duì)象。

因此,通過(guò)任意一個(gè)變量修改對(duì)象的屬性,都會(huì)影響到所有引用該對(duì)象的變量——因?yàn)樗鼈儾僮鞯氖峭粋€(gè)堆內(nèi)存中的對(duì)象。

// 引用數(shù)據(jù)類(lèi)型:Object
var x = { m: 1 };
// 賦值:把 x 的引用地址復(fù)制給 y
var y = x;

// 通過(guò) x 修改對(duì)象屬性
x.m++; // 對(duì)象的 m 屬性變成 2

// 查看 y.m:受影響,因?yàn)?x 和 y 指向同一個(gè)對(duì)象
console.log(y.m); // 輸出 2

// 反過(guò)來(lái),通過(guò) y 修改對(duì)象屬性,x 也會(huì)受影響
y.m = 10;
console.log(x.m); // 輸出 10

數(shù)組作為引用類(lèi)型,表現(xiàn)也是一樣的:

var arr1 = [1, 2, 3];
var arr2 = arr1;

arr1.push(4); // 給 arr1 新增元素
console.log(arr2); // 輸出 [1, 2, 3, 4],arr2 也跟著變

四、為什么要設(shè)計(jì)成這樣?—— 性能優(yōu)化的考量

可能會(huì)有疑問(wèn):為什么不把引用類(lèi)型也直接存儲(chǔ)在棧內(nèi)存,搞成“值復(fù)制”呢?這其實(shí)是 JS 引擎的性能優(yōu)化策略。

  • 對(duì)于基本類(lèi)型:體積小、結(jié)構(gòu)簡(jiǎn)單,值復(fù)制的開(kāi)銷(xiāo)非常低,直接存在棧內(nèi)存中,訪問(wèn)速度快;
  • 對(duì)于引用類(lèi)型:體積可能很大(比如一個(gè)包含上千個(gè)屬性的對(duì)象),如果每次賦值都復(fù)制整個(gè)對(duì)象,會(huì)占用大量的內(nèi)存空間,而且復(fù)制過(guò)程會(huì)消耗很多時(shí)間,嚴(yán)重影響程序性能。而復(fù)制一個(gè)小小的引用地址,開(kāi)銷(xiāo)幾乎可以忽略不計(jì)。

簡(jiǎn)單來(lái)說(shuō),這種設(shè)計(jì)是“空間”與“時(shí)間”的權(quán)衡——用“引用地址”的方式,減少內(nèi)存占用,提升程序運(yùn)行效率。

五、關(guān)鍵總結(jié):一張表理清所有差異

為了方便大家記憶,我們把兩種數(shù)據(jù)類(lèi)型的核心差異整理成表格:

對(duì)比維度基本數(shù)據(jù)類(lèi)型引用數(shù)據(jù)類(lèi)型
存儲(chǔ)位置棧內(nèi)存(直接存儲(chǔ)值)堆內(nèi)存存儲(chǔ)值,棧內(nèi)存存儲(chǔ)引用地址
賦值行為復(fù)制實(shí)際值,生成獨(dú)立副本復(fù)制引用地址,共享同一個(gè)對(duì)象
變量間關(guān)系互相獨(dú)立,互不影響指向同一對(duì)象,修改互相影響
修改方式直接修改變量的值(本質(zhì)是重新賦值)通過(guò)引用地址修改堆內(nèi)存中對(duì)象的屬性
典型示例let a = 10; let b = a; a = 20; b 仍為 10let obj1 = {x:1}; let obj2 = obj1; obj1.x=2; obj2.x 為 2

六、實(shí)用擴(kuò)展:如何避免引用類(lèi)型的“共享”問(wèn)題?

在實(shí)際開(kāi)發(fā)中,我們有時(shí)不希望多個(gè)變量共享同一個(gè)對(duì)象——比如我們想基于一個(gè)現(xiàn)有對(duì)象創(chuàng)建一個(gè)新對(duì)象,修改新對(duì)象時(shí)不影響原對(duì)象。這時(shí)候就需要用到深拷貝(Deep Copy) 技術(shù)。

深拷貝的核心是:創(chuàng)建一個(gè)全新的對(duì)象,把原對(duì)象的所有屬性(包括嵌套屬性)都復(fù)制到新對(duì)象中,新對(duì)象和原對(duì)象完全獨(dú)立,修改其中一個(gè)不會(huì)影響另一個(gè)。

這里給大家提供兩種常用的深拷貝方案:

6.1 簡(jiǎn)單場(chǎng)景:JSON 序列化/反序列化

適合沒(méi)有函數(shù)、Date、RegExp 等特殊屬性的普通對(duì)象/數(shù)組:

var obj1 = { m: 1, arr: [1, 2, 3] };
// 深拷貝:先序列化成 JSON 字符串,再反序列化成新對(duì)象
var obj2 = JSON.parse(JSON.stringify(obj1));

// 修改 obj2 的屬性和數(shù)組
obj2.m = 10;
obj2.arr.push(4);

// 原對(duì)象 obj1 不受影響
console.log(obj1); // 輸出 { m: 1, arr: [1, 2, 3] }
console.log(obj2); // 輸出 { m: 10, arr: [1, 2, 3, 4] }

6.2 通用場(chǎng)景:遞歸實(shí)現(xiàn)深拷貝

適合包含函數(shù)、Date 等特殊屬性的對(duì)象,兼容性更強(qiáng):

// 遞歸深拷貝函數(shù)
function deepClone(target) {
  // 先判斷是否是基本類(lèi)型或 null,直接返回
  if (typeof target !== 'object' || target === null) {
    return target;
  }

  // 初始化新對(duì)象/新數(shù)組
  let cloneTarget = Array.isArray(target) ? [] : {};

  // 遍歷原對(duì)象的所有屬性,遞歸復(fù)制
  for (let key in target) {
    if (target.hasOwnProperty(key)) {
      cloneTarget[key] = deepClone(target[key]);
    }
  }

  return cloneTarget;
}

// 測(cè)試:包含函數(shù)的對(duì)象
var obj1 = {
  m: 1,
  fn: function() { console.log('hello'); },
  arr: [1, 2, 3]
};

var obj2 = deepClone(obj1);
obj2.m = 10;
obj2.arr.push(4);

console.log(obj1.m); // 1(不受影響)
console.log(obj1.arr); // [1,2,3](不受影響)
obj1.fn(); // hello(函數(shù)屬性也能正常復(fù)制)
obj2.fn(); // hello

七、最后:一句話(huà)記住核心要點(diǎn)

基本類(lèi)型存棧里,賦值復(fù)制值,變量獨(dú)立;引用類(lèi)型存堆里,賦值復(fù)制地址,變量共享;想避免共享,就用深拷貝。

到此這篇關(guān)于JS數(shù)據(jù)類(lèi)型之基本類(lèi)型與引用類(lèi)型核心差異的文章就介紹到這了,更多相關(guān)JS基本類(lèi)型與引用類(lèi)型差異內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • javascript中offset、client、scroll的屬性總結(jié)

    javascript中offset、client、scroll的屬性總結(jié)

    這篇文章主要介紹了javascript中offset、client、scroll的屬性總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2015-08-08
  • JS實(shí)現(xiàn)簡(jiǎn)單圖片輪播效果

    JS實(shí)現(xiàn)簡(jiǎn)單圖片輪播效果

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)簡(jiǎn)單圖片輪播效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • JavaScript兩種計(jì)時(shí)器的實(shí)例講解

    JavaScript兩種計(jì)時(shí)器的實(shí)例講解

    今天小編就為大家分享一篇關(guān)于JavaScript兩種計(jì)時(shí)器的實(shí)例講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-01-01
  • json字符串對(duì)象轉(zhuǎn)換代碼實(shí)例

    json字符串對(duì)象轉(zhuǎn)換代碼實(shí)例

    這篇文章主要介紹了json字符串對(duì)象轉(zhuǎn)換代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • 用循環(huán)或if語(yǔ)句從json中取數(shù)據(jù)示例

    用循環(huán)或if語(yǔ)句從json中取數(shù)據(jù)示例

    倘若想將id和pid數(shù)據(jù)依次取出,就只能用循環(huán),若想有選擇性的輸出時(shí),需要添加if條件
    2014-08-08
  • JS刷新框架外頁(yè)面七種實(shí)現(xiàn)代碼

    JS刷新框架外頁(yè)面七種實(shí)現(xiàn)代碼

    JS刷新框架想必大家們都有所了解,如何是刷新框架外頁(yè)面想必大家有所陌生啦,沒(méi)關(guān)系本文的出現(xiàn)將解決大家的燃眉之急,感興趣的你可不要錯(cuò)過(guò)了哈
    2013-02-02
  • js中各瀏覽器中鼠標(biāo)按鍵值的差異

    js中各瀏覽器中鼠標(biāo)按鍵值的差異

    我們知道標(biāo)準(zhǔn)鼠標(biāo)有左,中,右三個(gè)鍵。鼠標(biāo)按下時(shí)如何判斷按下的是哪個(gè)鍵呢?
    2011-04-04
  • 基于js實(shí)現(xiàn)的圖片拖拽排序源碼實(shí)例

    基于js實(shí)現(xiàn)的圖片拖拽排序源碼實(shí)例

    這篇文章主要給大家介紹了關(guān)于如何基于js實(shí)現(xiàn)的圖片拖拽排序的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • js替換字符串中所有指定的字符(實(shí)現(xiàn)代碼)

    js替換字符串中所有指定的字符(實(shí)現(xiàn)代碼)

    下面小編就為大家?guī)?lái)一篇js替換字符串中所有指定的字符(實(shí)現(xiàn)代碼)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08
  • 很棒的js選項(xiàng)卡切換效果

    很棒的js選項(xiàng)卡切換效果

    很棒的JavaScript選項(xiàng)卡切換效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-07-07

最新評(píng)論

普安县| 永新县| 开封市| 郁南县| 江源县| 南京市| 修水县| 桓仁| 布尔津县| 砀山县| 凤阳县| 霍林郭勒市| 汾阳市| 建阳市| 巍山| 县级市| 黎平县| 温宿县| 贵德县| 商水县| 镶黄旗| 昌黎县| 潮州市| 淳安县| 徐州市| 昌宁县| 昌江| 蕲春县| 宁强县| 封开县| 北宁市| 郯城县| 兰坪| 恩施市| 津市市| 伊宁市| 华容县| 鲁山县| 天门市| 黄平县| 潞西市|