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

js中區(qū)分深拷貝與淺拷貝的實戰(zhàn)過程

 更新時間:2022年01月28日 10:09:21   作者:不知名前端李小白  
兩個對象A、B,A有數(shù)據(jù)B為空,B復(fù)制了A,我們修改A,如果B中的數(shù)據(jù)跟著變化了,那就是淺拷貝,如果沒有變化,那就是深拷貝,下面這篇文章主要給大家介紹了關(guān)于js中區(qū)分深拷貝與淺拷貝的相關(guān)資料,需要的朋友可以參考下

一、自我理解

簡單來講就是:深拷貝層層拷貝,淺拷貝只拷貝第一層。

在深拷貝中,新對象中的更改不會影響原對象,而在淺拷貝中,新對象中的更改,原對象中也會跟著改。

在深拷貝中,原對象與新對象不共享相同的屬性,而在淺拷貝中,它們具有相同的屬性。

舉個栗子:存在A和B兩個數(shù)據(jù),假設(shè)B復(fù)制了A,當(dāng)修改A時,如果B跟著A變化了,則是淺拷貝;如果B不受A的改變而改變,則是深拷貝

let A = [0,1,2]
let B = A
console.log(A === B);
A[0] = 3
console.log(A,B);

結(jié)果如下:

這就是一個簡單的淺拷貝例子,雖然B復(fù)制了A,但是修改了A,B卻跟著A變化了?

二、數(shù)據(jù)存儲形式

通過上述栗子,我們就需要了解數(shù)據(jù)類型的存儲方式了,如果還沒有了解數(shù)據(jù)類型的小伙伴歡迎閱讀 JS中8種數(shù)據(jù)類型

  • 基本數(shù)據(jù)類型:number,string,boolean,null,undefined,symbol(es6),還有谷歌67版本中的BigInt(任意精度整數(shù))
  • 引用數(shù)據(jù)類型:Object【Object是個大類,function函數(shù)、array數(shù)組、date日期...等都?xì)w屬于Object】

(1)基本數(shù)據(jù)類型存儲于棧中

變量名和值都存儲與棧中

每當(dāng)聲明一個變量,就會開辟一個新的內(nèi)存空間來存儲值,例如:let a = 1

// 聲明一個變量
let a = 1;

當(dāng)b復(fù)制了a后,因為b也是一個變量,所以棧內(nèi)存會再開辟一個新的內(nèi)存空間:

// 聲明一個變量
let a = 1;
let b = a; //b變量復(fù)制a變量
console.log(a,b); //1 1

這就一目了然了,a和b兩個變量歸屬于不同的內(nèi)存空間,所以當(dāng)你修改其中一個值,另外一個值不會受其影響!

// 聲明一個變量
let a = 1;
let b = a; //b變量復(fù)制a變量
console.log(a,b); //1 1 
// 修改a的值不影響b
a = 123;
console.log(a,b); //123 1

(2)引用數(shù)據(jù)類型存儲與堆中

變量名存儲在棧中,值存在于堆中,這時棧內(nèi)存中會提供一個指針用于指向堆內(nèi)存中的值

當(dāng)我們聲明一個引用數(shù)據(jù)類型時,會提供一個指針指向堆內(nèi)存中的值:

// 聲明一個引用類型的值
let a = [0,1,2,3,4]

當(dāng)b復(fù)制了a后,只是復(fù)制了當(dāng)前棧內(nèi)存中提供的指針,指向同一個堆內(nèi)存中的值,并不是復(fù)制了堆內(nèi)存中的值:

let a = [0,1,2,3,4]
let b = a //復(fù)制的是一個指針,而不是堆中的值

所以當(dāng)我們進(jìn)行a[0]=1時,導(dǎo)致指針?biāo)赶虻亩褍?nèi)存中的值發(fā)生了改變,而a和b是同一個指針,指向同一個堆內(nèi)存地址,所以b的值也會受影響,這就是淺拷貝!

// 聲明一個引用類型的值
let a = [0,1,2,3,4];
let b = a; //復(fù)制的是一個指針,而不是堆中的值
console.log(a === b);
a[0] = 1; //改變a數(shù)組值,b數(shù)組跟著改變(淺拷貝)
console.log(a,b);

所以,我們需要在堆內(nèi)存中新開辟一個內(nèi)存專門接收存儲b的值,道理與基本數(shù)據(jù)類型一樣,這樣就可以實現(xiàn)深拷貝(修改一個值不會影響另一個值的變化):

三、怎樣實現(xiàn)深拷貝?

(1)借助JSON對象的parse和stringify

parse()方法用于將一個字符串解析為json對象

stringify()方法用于將一個對象解析為字符串

// 淺拷貝
let arr = [1,"hello",{name:"張三",age:21}]
let copyArr = arr
console.log(arr === copyArr); //true
arr[1] = "您好"
console.log("淺拷貝",arr, copyArr);

// JSON對象方法實現(xiàn)深拷貝
let arr = [1,"hello",{name:"張三",age:21}]
let newArr = JSON.parse(JSON.stringify(arr)) //將arr數(shù)組轉(zhuǎn)換為字符串,再作為參數(shù)轉(zhuǎn)化為對象
arr[1] = "您好"
arr[2].name = "法外狂徒"
console.log("深拷貝",arr, newArr);

原理是利用JSON.stringify將對象轉(zhuǎn)成JSON字符串,再用JSON.parse把字符串解析成對象,這樣在堆中開辟了新的內(nèi)存,實現(xiàn)深拷貝

這種寫法非常簡單,而且可以應(yīng)對大部分的應(yīng)用場景,但是它還是有很大缺陷的,比如拷貝其他引用類型、拷貝函數(shù)、循環(huán)引用等情況

(2)手寫遞歸

遞歸方法實現(xiàn)深度克隆原理:遍歷對象、數(shù)組...直到里邊都是基本數(shù)據(jù)類型,然后再去復(fù)制,就是深度拷貝

  • 如果是原始類型,無需繼續(xù)拷貝,直接返回
  • 如果是引用類型,創(chuàng)建一個新的對象,遍歷需要克隆的對象,將需要克隆對象的屬性執(zhí)行深拷貝后依次添加到新對象上
// 手寫遞歸實現(xiàn)深拷貝
function clone(target) {
    if (typeof target === 'object') {
        // 創(chuàng)建一個新對象
        let cloneTarget = {};
        // 遍歷需要克隆的對象
        for (const key in target) {
            // 將需要克隆對象的屬性執(zhí)行深拷貝后依次添加到新對象上
            cloneTarget[key] = clone(target[key]);
        }
        // 返回克隆對象
        return cloneTarget;
    } else {
        return target;
    }
};
// 模擬拷貝對象
const person = {
    name: "李小白",
    age: 18,
    job: {
        name:"web前端",
        salary:"15k",
        address:"成都"
    }
};
// 將需要克隆的對象傳遞給clone函數(shù)作為參數(shù),接收一個克隆對象作為返回結(jié)果
let newTarget = clone(person)
//修改原對象屬性
person["name"] = "李大白" 
person["job"]["salary"] = "25k" 
console.log(person,newTarget); //實現(xiàn)深拷貝

利用遞歸可以實現(xiàn)深度拷貝,但是有局限性,例如數(shù)組還沒考慮進(jìn)去!

想要兼容數(shù)組其實很簡單,直接判斷一下參數(shù)是不是數(shù)組,然后利用三木運算決定是創(chuàng)建一個新對象還是一個新數(shù)組:

function clone(target) {
    if (typeof target === 'object') {
        let isArr = Array.isArray(target)
        // 判斷傳入的參數(shù)是數(shù)組嗎 ? 是則賦值[] : 否則賦值{}
        let cloneTarget = isArr ? [] : {};
        // 遍歷需要克隆的對象
        for (const key in target) {
            // 將需要克隆對象的屬性執(zhí)行深拷貝后依次添加到新對象上
            cloneTarget[key] = clone(target[key]);
        }
        // 返回克隆對象
        return cloneTarget;
    } else {
        return target;
    }
};

(3)JQuery中extend方法

在jQuery中提供一個$extend()來實現(xiàn)深拷貝

語法:

$.extend( [deep ], target, object1 [, objectN ] )
  • deep 表示是否深拷貝,為true為深拷貝,為false,則為淺拷貝
  • target Object類型 目標(biāo)對象,其他對象的成員屬性將被附加到該對象上。
  • object1  objectN可選。 Object類型 第一個以及第N個被合并的對象。
let arr = ["李小白",18,["前端","15k"],21]
// true:開啟深拷貝,目標(biāo)對象:[],原對象:arr
let cloneArr = $.extend(true, [], arr)
arr[0] = "李大白";
arr[2][0] = "java";
console.log(arr, cloneArr);

$extend()第一個參數(shù)為true時可以實現(xiàn)深拷貝!但是第一個參數(shù)為false,則只會拷貝第一層屬性,不能實現(xiàn)深拷貝:

let arr = ["李小白",18,["前端","15k"],21]
// false:不開啟深拷貝,目標(biāo)對象:[],原對象:arr
let cloneArr = $.extend(false, [], arr)
arr[0] = "李大白";
arr[2][0] = "java";
console.log(arr, cloneArr);

總結(jié)/注意

實現(xiàn)深拷貝方式有多種,以上三種較為常用,另外還有一個:函數(shù)庫lodash中_.cloneDeep方法(本人未使用過)也可以實現(xiàn)深拷貝。

最后需要補充一下,網(wǎng)上有很多人說slice和concat方法可以實現(xiàn),但我要說的是slice和concat方法不能實現(xiàn)深拷貝的!?。?/p>

下面舉例說明:

// slice()
let arr = [0,1,["hello","world"]];
let cloneArr = arr.slice();
arr[0] = "零";
arr[2][0] = "hello2022"
console.log(arr,cloneArr);
// concat()
let arr = [0,1,["hello","world"]];
let cloneArr = arr.concat();
arr[0] = "零";
arr[2][0] = "hello2022"
console.log(arr,cloneArr);

這兩個方法得到的結(jié)果都是一樣的:

這一點大家一定要注意,深拷貝必須要拷貝所有層級的屬性,而這兩個方法拷貝不徹底,也就是只能拷貝第一層,希望大家不要踩坑!

總結(jié)

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

相關(guān)文章

  • echarts餅圖labelLine線的長度自適應(yīng)設(shè)置

    echarts餅圖labelLine線的長度自適應(yīng)設(shè)置

    這篇文章主要給大家介紹了關(guān)于echarts餅圖labelLine線的長度自適應(yīng)設(shè)置的相關(guān)資料,在echarts中,餅圖的標(biāo)簽線可以通過設(shè)置 labelLine屬性來自定義位置,需要的朋友可以參考下
    2023-08-08
  • js window.onload 加載多個函數(shù)和追加函數(shù)詳解

    js window.onload 加載多個函數(shù)和追加函數(shù)詳解

    本篇文章主要是對js window.onload 加載多個函數(shù)和追加函數(shù)進(jìn)行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-01-01
  • JS組件系列之Bootstrap table表格組件神器【二、父子表和行列調(diào)序】

    JS組件系列之Bootstrap table表格組件神器【二、父子表和行列調(diào)序】

    本文結(jié)合Bootstrap table的父子表和行列調(diào)序的用法再來介紹下它稍微高級點的用法。對bootstrap表格組件相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧
    2016-05-05
  • JS實現(xiàn)的點擊按鈕圖片上下滾動效果示例

    JS實現(xiàn)的點擊按鈕圖片上下滾動效果示例

    這篇文章主要介紹了JS實現(xiàn)的點擊按鈕圖片上下滾動效果,涉及javascript事件響應(yīng)及頁面元素屬性動態(tài)操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2019-01-01
  • JavaScript簡單獲取頁面圖片原始尺寸的方法

    JavaScript簡單獲取頁面圖片原始尺寸的方法

    這篇文章主要介紹了JavaScript簡單獲取頁面圖片原始尺寸的方法,可通過Image()對象直接獲取圖片的原始寬高,簡單實用,需要的朋友可以參考下
    2016-06-06
  • JavaScript十大取整方法實例教程

    JavaScript十大取整方法實例教程

    這篇文章主要給大家介紹了關(guān)于JavaScript的十大取整方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • JS實現(xiàn)深拷貝的幾種簡單方法示例

    JS實現(xiàn)深拷貝的幾種簡單方法示例

    深拷貝和淺拷貝是在JavaScript中復(fù)制對象或數(shù)組時經(jīng)常遇到的概念,下面這篇文章主要給大家介紹了關(guān)于JS實現(xiàn)深拷貝的幾種簡單方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-10-10
  • JS原型對象的創(chuàng)建方法詳解

    JS原型對象的創(chuàng)建方法詳解

    這篇文章主要介紹了JS原型對象的創(chuàng)建方法,結(jié)合實例形式詳細(xì)分析了js對象的創(chuàng)建方法與相關(guān)注意事項,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • js中的replace方法使用介紹

    js中的replace方法使用介紹

    replace() 方法用于將字符串用一些字符替換另一些字符,如果用正則表達(dá)式替換時, regexp 具有全局標(biāo)志 g,下面有個不錯的示例,感興趣的朋友可以參考下
    2013-10-10
  • js中el表達(dá)式的使用和非空判斷方法

    js中el表達(dá)式的使用和非空判斷方法

    下面小編就為大家分享一篇js中el表達(dá)式的使用和非空判斷方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03

最新評論

越西县| 高淳县| 丁青县| 昌邑市| 秦皇岛市| 平顺县| 赤水市| 北安市| 如皋市| 万州区| 双辽市| 深水埗区| 大庆市| 泰来县| 武川县| 台北市| 株洲市| 永州市| 林口县| 丁青县| 浦北县| 馆陶县| 安西县| 荥经县| 新乐市| 门头沟区| 周至县| 隆回县| 应城市| 东宁县| 临沂市| 福州市| 云南省| 三亚市| 北海市| 邵东县| 金平| 吴江市| 绥阳县| 苏州市| 二手房|