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

JavaScript?賦值,淺復制和深復制的區(qū)別

 更新時間:2022年05月25日 16:34:01   作者:??大力yy????  
這篇文章主要介紹了JavaScript?賦值,淺復制和深復制的區(qū)別,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下

前言:

淺復制和深復制可以說是面試中很常見的一道題了,本文就來聊一聊JavaScript中的淺復制和深復制。

一、變量賦值

不知道會不會有人會和我一樣,會覺得淺復制就是通過=操作符將一個變量賦值給另外一個變量。但實際上,淺復制和變量賦值之間是存在區(qū)別的。所以,我們先來了解一下變量賦值。

1.1 原始值和引用值

原始值(primitive value):最簡單的數(shù)據(jù),即:Undefined、Null、Boolean、Number、String、BigInt、Symbol這其中類型的值。保存原始值的變量是按值訪問的,我們操作的就是存儲在變量中的實際值。

引用值(reference value):有多個值構(gòu)成的對象,即 Object 類型。引用值是保存在內(nèi)存中的對象,但是 JavaScript 不允許直接訪問內(nèi)存位置,所以不能直接操作對象所在的內(nèi)存空間。在操作對象時,實際操作的是該對象的引用(reference) 而非實際的對象本身。保存引用值得變量實際上存儲得是對象得引用,是按引用訪問得。

1.2 賦值

首先說明這里說的賦值,不是直接把引用值(例如:{})或者原始值(例如:false、1、"str"等)直接賦值給一個變量。而是通過變量把一個值賦值給另一個變量。

原始值賦值:保存原始值的變量是按值訪問的,所以通過變量把一個原始值賦值給另一個變量時,原始值會被復制到新變量的位置。

let num1 = 5;
let num2 = num1;
console.log(num1, num2);  // 5 5
num2 = 4;
console.log(num1, num2);  // 5 4

可以看出 num2 通過 num1 被賦值為5,保存的是同一個原始值。而且兩個變量相互獨立,互不干擾。

具體賦值過程如下:

引用值賦值:保存引用值的變量是按引用訪問的,通過變量把一個引用賦值給另一個變量時,存儲在變量中的值也會被復制到新變量的位置。但是,這里復制的實際上是一個指向存儲在堆內(nèi)存中對象的指針。賦值后,兩個變量實際上指向同一個對象。所以兩個變量通過引用對對象的操作會互相影響。

let obj1 = {};
let obj2 = obj1;
console.log(obj1);  // {}
console.log(obj2);  // {}
obj1.name = 'haha';
console.log(obj1);  // { name: 'haha' }
console.log(obj2);  // { name: 'haha' }
obj1.age = 24;
console.log(obj1);  // { name: 'haha', age: 24 }
console.log(obj2);  // { name: 'haha', age: 24 }

如上代碼,通過 obj1 將指向?qū)ο蟮囊觅x值給 obj2后, obj1 和 obj2 保存了指向同一對象的引用,所以操作的是同一對象。

具體可見下圖:

注:如上兩圖來自《JavaScript 高級程序設(shè)計(第四版)》

接下來要說的淺復制和深復制就是針對引用值而言的。

二、淺復制(Shallow Copy)

我們先來看一篇博客中對于淺復制的定義:

An object is said to be shallow copied when the source top-level properties are copied without any reference and there exist a source property whose value is an object and is copied as a reference. If the source value is a reference to an object, it only copies that reference value to the target object.

對此,個人的理解淺復制就是復制該對象的的每個屬性,如果該屬性值是原始值,則復制該原始值,如果屬性值是一個對象,那么就復制該對象的引用。

即:淺復制將復制頂層屬性,但嵌套對象在原始(源)和拷貝(目標)之間共享

2.1 原生 JavaScript 中的淺復制

Object.assign()

Object.assign()方法將所有可枚舉(Object.propertyIsEnumerable()返回 true)和自有(Object.hasOwnProperty()返回 true)屬性從一個或多個源對象復制(淺復制) 到目標對象,返回修改后的對象。

如下代碼可以看出,淺復制和變量賦值不同,修改對象的屬性值互不影響。

const source = { a: 1, b: 2 };
const objCopied = Object.assign({}, source);

console.log(objCopied); // { a: 1, b: 2 }

source.a = 3;
console.log(source);  // { a: 3, b: 2 }
console.log(objCopied);  // { a: 1, b: 2 }

objCopied.a = 4;
console.log(source);  // { a: 3, b: 2 }
console.log(objCopied);  // { a: 4, b: 2 }

對象內(nèi)的嵌套對象在源對象和拷貝對象之間還是共享的,如上代碼,修改對象內(nèi)對象的屬性時會相互影響。

const source = { a : {b : 1} };
const objCopied = Object.assign({}, source);

console.log(objCopied); // { a: { b: 1 } }

source.a.b = 3;
console.log(source);  // { a: { b: 3 } }
console.log(objCopied);  // { a: { b: 3 } }

但是注意如下代碼中,source.a = {};修改的是源對象中屬性的值,這個并不共享。

const source = { a : {b : 1} };
const objCopied = Object.assign({}, source);

console.log(objCopied); // { a: { b: 1 } }

source.a = {};
console.log(source);  // { a: {} }
console.log(objCopied);  // { a: { b: 1 } }

展開運算符(...):展開語法(Spread syntax), 可以在函數(shù)調(diào)用/數(shù)組構(gòu)造時, 將數(shù)組表達式或者string在語法層面展開;還可以在構(gòu)造字面量對象時, 將對象表達式按key-value的方式展開。

const source = { a : {b : 1}, c: 2 };
const objCopied = {...source}

console.log(objCopied); // { a: { b: 1 }, c: 2 }

source.c = 3;
console.log(source);  // { a: { b: 1 }, c: 3 }
console.log(objCopied);  // { a: { b: 1 }, c: 2 }

source.a.b = 3;
console.log(source);  // { a: { b: 3 }, c: 3 }
console.log(objCopied);  // { a: { b: 3 }, c: 2 }

2.2 淺復制的手動實現(xiàn)

function shallowClone(source) {
    // 如果是原始值,直接返回
    if (typeof source !== 'object') {
        return source;
    }

    // 拷貝后的對象
    const copied = Array.isArray(source) ? [] : {};
    // 遍歷對象的key
    for(let key in source) {
        // 如果key是對象的自有屬性
        if(source.hasOwnProperty(key)) {
            // 復制屬性
            copied[key] = source[key]
        }
    }

    // 返回拷貝后的對象
    return copied;
}

三、深復制(Deep Copy)

首先來看深復制的定義:

A deep copy will duplicate every object it encounters. The copy and the original object will not share anything, so it will be a copy of the original.

與淺復制不同時,當源對象屬性的值為對象時,賦值的是該對象,而不是對象的引用。所以深復制中,源對象和拷貝對象之間不存在任何共享的內(nèi)容。

2.1 原生 JavaScript 中的深復制

JSON.parse(JSON.stringify(object))

JavaScript 中最常見的深復制的方法就是JSON.parse(JSON.stringify(object))

如下代碼所示,深復制中源對象和拷貝對象不共享任何內(nèi)容,即使是嵌套對象。

let obj = {
    a: 1,
    b: {
        c: 2,
    },
}
let newObj = JSON.parse(JSON.stringify(obj));
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } }

2.2 深復制的手動實現(xiàn)

function deepClone(source) {
    // 如果是原始值,直接返回
    if (typeof source !== 'object') {
        return source;
    }
    // 拷貝后的對象
    const copied = Array.isArray(source) ? [] : {};
    // 遍歷對象的key
    for(let key in source) {
        // 如果key是對象的自有屬性
        if(source.hasOwnProperty(key)) {
            // 深復制
            copied[key] = deepClone(source[key]);
        }
    }
    return copied;
}

有關(guān)淺復制和深復制的手動實現(xiàn),這里只是簡單實現(xiàn)了一下。其中還有很多細節(jié)未實現(xiàn),具體的實現(xiàn)大家可以參見 lodash 中的實現(xiàn)。

小結(jié)

  • 賦值操作符是把一個對象的引用賦值給一個變量,所以變量中存儲的是對象的引用
  • 淺復制是復制源對象的每個屬性,但如果屬性值是對象,那么復制的是這個對象的引用。所以源對象和拷貝對象之間共享嵌套對象。
  • 深復制與淺復制不同的地方在于,如果屬性值為對象,那么會復制該對象。源對象和拷貝對象之間不存在共享的內(nèi)容。

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

相關(guān)文章

  • yepnope.js使用詳解及示例分享

    yepnope.js使用詳解及示例分享

    yepnope.js 是一個超高速的按條件異步加載資源的加載器,允許你只加載使用到的資源(css及js)。
    2014-06-06
  • 詳解微信小程序工程化探索之webpack實戰(zhàn)

    詳解微信小程序工程化探索之webpack實戰(zhàn)

    這篇文章主要介紹了詳解微信小程序工程化探索之webpack實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-04-04
  • JavaScript判斷表單為空及獲取焦點的方法

    JavaScript判斷表單為空及獲取焦點的方法

    這篇文章主要介紹了JavaScript判斷表單為空及獲取焦點的方法,可實現(xiàn)表單提交時判斷表單是否為空及獲取響應(yīng)焦點的功能,非常簡單實用,需要的朋友可以參考下
    2016-02-02
  • bootstrap按鈕插件(Button)使用方法解析

    bootstrap按鈕插件(Button)使用方法解析

    這篇文章主要為大家詳細解析了bootstrap按鈕插件Button使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • 詳解JavaScript前端加解密工具庫的使用

    詳解JavaScript前端加解密工具庫的使用

    這篇文章主要為大家詳細介紹了JavaScript前端加解密工具庫(CryptoJS、JSEncrypt、bcryptjs)的具體使用,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下
    2023-12-12
  • 原生js 實現(xiàn)表單驗證功能

    原生js 實現(xiàn)表單驗證功能

    這篇文章主要介紹了原生js如何實現(xiàn)表單驗證功能,幫助大家更好的理解和使用JavaScript,感興趣的朋友可以了解下
    2021-02-02
  • 在webstorm中配置less的方法詳解

    在webstorm中配置less的方法詳解

    這篇文章主要介紹了在webstorm中配置less的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2020-09-09
  • JavaScript中利用Array filter() 方法壓縮稀疏數(shù)組

    JavaScript中利用Array filter() 方法壓縮稀疏數(shù)組

    Array filter() 方法會跳過稀疏數(shù)組中缺少的元素,它的返回數(shù)組總是稠密的。這篇文章給大家介紹了JavaScript中利用Array filter() 方法壓縮稀疏數(shù)組的相關(guān)知識,需要的朋友參考下
    2018-02-02
  • 20個實用的JavaScript技巧分享

    20個實用的JavaScript技巧分享

    這篇文章主要介紹了20個實用的JavaScript技巧分享,本文講解的都是開發(fā)中總結(jié)出的編碼技巧、和最佳實踐,需要的朋友可以參考下
    2014-11-11
  • 微信小程序 授權(quán)登錄詳解(附完整源碼)

    微信小程序 授權(quán)登錄詳解(附完整源碼)

    這篇文章主要介紹了微信小程序 授權(quán)登錄詳解(附完整源碼),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-08-08

最新評論

剑川县| 庆安县| 慈利县| 昂仁县| 平果县| 磐安县| 锦州市| 江北区| 土默特左旗| 黔江区| 德庆县| 车险| 枝江市| 新平| 赫章县| 布拖县| 忻城县| 安达市| 鸡东县| 贺州市| 阿巴嘎旗| 松潘县| 建水县| 雅江县| 保靖县| 瓦房店市| 周口市| 锦屏县| 城固县| 汕尾市| 从江县| 东乡| 宁国市| 斗六市| 吴江市| 东乌珠穆沁旗| 商水县| 黄骅市| 万全县| 梓潼县| 积石山|