国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

淺談JavaScript的淺拷貝與深拷貝

娣辯孩 / 3158人閱讀

摘要:引用數(shù)據(jù)類型是存放在堆內(nèi)存中的,變量實(shí)際上是一個(gè)存放在棧內(nèi)存的指針,這個(gè)指針指向堆內(nèi)存中的地址。棧和堆的區(qū)別其實(shí)淺拷貝和深拷貝的主要區(qū)別就是數(shù)據(jù)在內(nèi)存中的存儲(chǔ)類型不同。這里,對(duì)存在子對(duì)象的對(duì)象進(jìn)行拷貝的時(shí)候,就是深拷貝了。

數(shù)據(jù)類型

在開(kāi)始拷貝之前,我們從JavaScript的數(shù)據(jù)類型和內(nèi)存存放地址講起。
數(shù)據(jù)類型分為基本數(shù)據(jù)類型引用數(shù)據(jù)類型

基本數(shù)據(jù)類型主要包括undefined,boolean,number, string,null。

基本數(shù)據(jù)類型主要存放在棧(stack),存放在棧中的數(shù)據(jù)簡(jiǎn)單,大小確定。存放在棧內(nèi)存中的數(shù)據(jù)是直接按值存放的,是可以直接訪問(wèn)的。

基本數(shù)據(jù)類型的比較是值的比較,只要它們的值相等就認(rèn)為它們是相等的。

let a = 1;
let b = 1;
console.log(a === b); //true

這里使用嚴(yán)格相等,主要是為了==會(huì)進(jìn)行類型轉(zhuǎn)換。

let a = true;
let b = 1;
console.log(a == b); //true

引用數(shù)據(jù)類型也就是對(duì)象類型Object type,比如object,array, function,date等。
引用數(shù)據(jù)類型是存放在堆(heap)內(nèi)存中的,變量實(shí)際上是一個(gè)存放在棧內(nèi)存的指針,這個(gè)指針指向堆內(nèi)存中的地址。

引用數(shù)據(jù)類型的比較是引用的比較
所以我們每次對(duì)js中的引用類型進(jìn)行操作的時(shí)候,都是操作其保存在棧內(nèi)存中的指針,所以比較兩個(gè)引用數(shù)據(jù)類型,是看它們的指針是否指向同一個(gè)對(duì)象。

let foo = {a: 1, b: 2};
let bar = {a: 1, b: 2};
console.log(foo === bar); //false

雖然變量foo和變量bar所表示的內(nèi)容是一樣的,但是其在內(nèi)存中的位置不一樣,也就是變量foo和bar在棧內(nèi)存中存放的指針指向的不是堆內(nèi)存中的同一個(gè)對(duì)象,所以它們是不相等的。

棧和堆的區(qū)別

其實(shí)淺拷貝和深拷貝的主要區(qū)別就是數(shù)據(jù)在內(nèi)存中的存儲(chǔ)類型不同。
棧和堆都是內(nèi)存中劃分出來(lái)用來(lái)存儲(chǔ)的區(qū)域。
棧(stack) 是自動(dòng)分配的內(nèi)存空間,由系統(tǒng)自動(dòng)釋放;
堆(heap) 則是動(dòng)態(tài)分配的內(nèi)存,大小不定也不會(huì)自動(dòng)釋放。

淺拷貝

如果你的對(duì)象只有值類型的屬性,可以用ES6的新語(yǔ)法Object.assign(...)實(shí)現(xiàn)拷貝

//淺拷貝
let obj = {foo: "foo", bar: "bar"};

let shallowCopy = { ...obj };  //{foo: "foo", bar: "bar"}
//淺拷貝
let obj = {foo: "foo", bar: "bar"};

let shallowCopy = Object.assign({}, obj); //{foo: "foo", bar: "bar"}

我們接著來(lái)看下淺拷貝和賦值(=) 的區(qū)別

let obj = {foo: "foo", bar: "bar"};
let shallowCopy = { ...obj }; //{foo: "foo", bar: "bar"}
let obj2= obj; //{foo: "foo", bar: "bar"}
shallowCopy.foo = 1;
obj2.bar = 1
console.log(obj); //{foo: "foo", bar: 1};

可以看出賦值得到的obj2和最初的obj指向的是同一對(duì)象,改變數(shù)據(jù)會(huì)使原數(shù)據(jù)一同改變。
而淺拷貝得到的shallowCopy則將obj的第一層數(shù)據(jù)對(duì)象拷貝到了,和源數(shù)據(jù)不指向同一對(duì)象,改變不會(huì)使原數(shù)據(jù)一同改變。

深拷貝

但是Object.assign(...)方法只能進(jìn)行對(duì)象的一層拷貝。對(duì)于對(duì)象的屬性是對(duì)象的對(duì)象,他不能進(jìn)行深層拷貝。
迷糊了吧?直接代碼解釋

let foo = {a: 0, b: {c: 0}};
let copy = { ...foo };
copy.a = 1;
copy.b.c = 1;
console.log(copy); //{a: 1, b: {c: 1}};
console.log(foo); //{a: 0, b: {c: 1}};

可以看到,使用Object.assign(...)方法拷貝的copy對(duì)象的二層對(duì)象發(fā)生改變的時(shí)候,依然會(huì)使原數(shù)據(jù)一同改變。
這里,對(duì)存在子對(duì)象的對(duì)象進(jìn)行拷貝的時(shí)候,就是深拷貝了。

淺拷貝:將B對(duì)象拷貝到A對(duì)象中,不包括B里面的子對(duì)象
深拷貝:將B對(duì)象拷貝到A對(duì)象中,包括B里面的子對(duì)象

深拷貝實(shí)現(xiàn)的方法:

這里只說(shuō)幾種常用方法,
1.JSON.parse(JSON.stringify( ));

    let foo = {a: 0, b: {c: 0}};
       let copy = JSON.parse(JSON.stringify(foo));
       copy.a = 1;
       copy.b.c = 1;

       console.log(copy); //{a: 1, b: {c: 1}};
       console.log(foo); //{a: 0, b: {c: 0}};

2.遞歸拷貝

    function deepCopy(initialObj, finalObj){
            let obj = finalObj || {};
            for(let i in initialObj) {
                if(typeof initialObj[i] === "object") {
                    obj[i] = (initialObj[i].constructor === Array) ? [] : {};
                    arguments.callee(initialObj[i], obj[i]);
                }else{
                    obj[i] = initialObj[i];
                }
            }
            return obj;
        }


        var foo = {a: 0, b: {c: 0}};
        var str = {};

        deepCopy(foo, str);

        str.a = 1;
        str.b.c = 1;

        console.log(str); //{a: 1, b: {c: 1}};
        console.log(foo); //{a: 0, b: {c: 0}};

上述代碼確實(shí)可以實(shí)現(xiàn)深拷貝,但是當(dāng)遇到兩個(gè)互相引用的對(duì)象,會(huì)出現(xiàn)死循環(huán)的情況。

為了避免相互引用的對(duì)象導(dǎo)致死循環(huán)的情況,則應(yīng)該在遍歷的時(shí)候判斷是否相互引用對(duì)象,如果是則退出循環(huán)。

改進(jìn)版代碼如下:

        function deepCopy(initialObj, finalObj) {
            let obj = finalObj || {};
            for(let i in initialObj){
                let prop = initialObj[i];//避免相互引用導(dǎo)致死循環(huán),如initialObj.a = initialObj的情況
                if(prop === obj) {
                    continue;
                }
                if(typeof prop === "object"){
                    obj[i] = (prop.constructor === Array) ? [] : {};
                    arguments.callee(prop, obj[i]);
                }else{
                    obj[i] = prop;
                }
            }
            return obj;
        }


        var foo = {a: 0, b: {c: 0}};
        var str = {};

        deepCopy(foo, str);

        str.a = 1;
        str.b.c = 1;

        console.log(str); //{a: 1, b: {c: 1}};
        console.log(foo); //{a: 0, b: {c: 0}};

3.使用Object.create( )方法

        function deepCopy(initialObj, finalObj){
            let obj = finalObj || {};
            for(let i in initialObj){
                let prop = initialObj[i];  //避免相互引用對(duì)象導(dǎo)致死循環(huán),如initialObj[i].a = initialObj的情況
                if(prop === obj){
                    continue;
                }
                if(typeof prop === "object"){
                    obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
                }else{
                    obj[i] = prop;
                }
            }
            return obj;
        }


        let foo = {a: 0, b: {c: 0}};
        let str = {};

        deepCopy(foo, str);

        str.a = 1;
        str.b.c = 1;

        console.log(str); //{a: 1, b: {c: 1}};
        console.log(foo); //{a: 0, b: {c: 0}};

4.jQuery

jQuery提供了一個(gè)$.extend可以實(shí)現(xiàn)深拷貝

var $ = require("jquery);

let foo = {a: 0, b: {c: 0}};
let str = $.extend(true, {}, foo);
str.a = 1;
str.b.c = 1;

console.log(str); //{a: 1, b: {c: 1}};
console.log(foo); //{a: 0, b: {c: 0}};

5.lodash
另一個(gè)很熱門的函數(shù)庫(kù)lodash,也有提供_.cloneDeep用來(lái)深拷貝

var _ = require("lodash);

let foo = {a: 0, b: {c: 0}};
let str = _.cloneDeep(foo);
str.a = 1;
str.b.c = 1;

console.log(str); //{a: 1, b: {c: 1}};
console.log(foo); //{a: 0, b: {c: 0}};

局限性
所有深拷貝的方法并不適用于所有類型的對(duì)象。當(dāng)然還有其他的坑,像是如何拷貝原型鏈上的屬性?如何拷貝不可枚舉屬性等等。
雖然lodash是最安全的通用深拷貝方法,但如果你自己動(dòng)手,可能會(huì)依據(jù)需求寫出最適合你的更高效的深拷貝的方法:

//適用于日期的簡(jiǎn)單深拷貝的例子
        function deepCopy(obj) {
            let copy;

            //處理三種簡(jiǎn)單的引用數(shù)據(jù)類型加上undefined和null
            if(obj == null || typeof obj != "object") return obj;

            //處理Date
            if(obj instanceof Date){
                copy = new Date();
                copy.setTime(obj.getTime());
                return copy;
            }

            //處理Array
            if(obj instanceof Array) {
                copy = [];
                for(let i = 0; i < obj.length; i++) {
                    copy[i] = deepCopy(obj[i]);
                }
                return copy;
            }

            //處理Function
            if(obj instanceof Function) {
                copy = function() {
                    return obj.apply(this, arguments);
                }
                return copy;
            }

            //處理Object
            if(obj instanceof Object) {
                copy = {};
                for(let attr in obj) {
                    if(obj.hasOwnProperty(attr)) copy[attr] = deepCopy(obj[attr]);
                }
                return copy;
            }


            throw new Error("無(wú)法深拷貝" +obj.constructor+ "類型的數(shù)據(jù)")
        }

快樂(lè)拷貝

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/99476.html

相關(guān)文章

  • 關(guān)于js的淺拷貝與深拷貝

    摘要:原文地址淺拷貝和深拷貝只針對(duì)像這樣的復(fù)雜對(duì)象的簡(jiǎn)單來(lái)說(shuō),淺拷貝只拷貝一層對(duì)象的屬性,而深拷貝則遞歸拷貝了所有層級(jí)。淺拷貝通過(guò)來(lái)實(shí)現(xiàn)淺拷貝。 原文地址:http://www.silenceboy.com/201... 淺拷貝和深拷貝只針對(duì)像Object, Array這樣的復(fù)雜對(duì)象的.簡(jiǎn)單來(lái)說(shuō),淺拷貝只拷貝一層對(duì)象的屬性,而深拷貝則遞歸拷貝了所有層級(jí)。 淺拷貝 通過(guò) Object.ass...

    summerpxy 評(píng)論0 收藏0
  • JavaScript的淺拷貝與深拷貝

    摘要:所以,深拷貝是對(duì)對(duì)象以及對(duì)象的所有子對(duì)象進(jìn)行拷貝實(shí)現(xiàn)方式就是遞歸調(diào)用淺拷貝對(duì)于深拷貝的對(duì)象,改變?cè)磳?duì)象不會(huì)對(duì)得到的對(duì)象有影響。 為什么會(huì)有淺拷貝與深拷貝什么是淺拷貝與深拷貝如何實(shí)現(xiàn)淺拷貝與深拷貝好了,問(wèn)題出來(lái)了,那么下面就讓我們帶著這幾個(gè)問(wèn)題去探究一下吧! 如果文章中有出現(xiàn)紕漏、錯(cuò)誤之處,還請(qǐng)看到的小伙伴多多指教,先行謝過(guò) 以下↓ 數(shù)據(jù)類型在開(kāi)始了解 淺拷貝 與 深拷貝 之前,讓我們先...

    546669204 評(píng)論0 收藏0
  • JavaScript的淺拷貝與深拷貝

    摘要:所以,深拷貝是對(duì)對(duì)象以及對(duì)象的所有子對(duì)象進(jìn)行拷貝實(shí)現(xiàn)方式就是遞歸調(diào)用淺拷貝對(duì)于深拷貝的對(duì)象,改變?cè)磳?duì)象不會(huì)對(duì)得到的對(duì)象有影響。 上一篇 JavaScript中的繼承 前言 文章開(kāi)始之前,讓我們先思考一下這幾個(gè)問(wèn)題: 為什么會(huì)有淺拷貝與深拷貝 什么是淺拷貝與深拷貝 如何實(shí)現(xiàn)淺拷貝與深拷貝 好了,問(wèn)題出來(lái)了,那么下面就讓我們帶著這幾個(gè)問(wèn)題去探究一下吧! 如果文章中有出現(xiàn)紕漏、錯(cuò)誤之處...

    AZmake 評(píng)論0 收藏0
  • 關(guān)于JavaScript的淺拷貝和深拷貝

    摘要:引用類型值引用類型值是保存在堆內(nèi)存中的對(duì)象,變量保存的只是指向該內(nèi)存的地址,在復(fù)制引用類型值的時(shí)候,其實(shí)只復(fù)制了指向該內(nèi)存的地址。 前言 要理解 JavaScript中淺拷貝和深拷貝的區(qū)別,首先要明白JavaScript的數(shù)據(jù)類型。JavaScript有兩種數(shù)據(jù)類型,基礎(chǔ)數(shù)據(jù)類型和引用數(shù)據(jù)類型。js的基本類型:undefined,null,string,boolean,number,s...

    shenhualong 評(píng)論0 收藏0
  • JS引用類型數(shù)據(jù)的淺拷貝與深拷貝

    摘要:拷貝到,屬性均順利拷貝。大輝小輝,小輝,大輝小輝,小輝,大輝但是,若修改的屬性變?yōu)閷?duì)象或數(shù)組時(shí),那么對(duì)象之間就會(huì)發(fā)生關(guān)聯(lián)。深拷貝不希望對(duì)象之間產(chǎn)生關(guān)聯(lián),那么這時(shí)候可以用到深拷貝。 淺拷貝 之前文章提到,在定義一個(gè)對(duì)象或數(shù)組時(shí),變量存放的往往只是一個(gè)地址。當(dāng)我們對(duì)堆內(nèi)存中的對(duì)象復(fù)制時(shí),如果屬性是對(duì)象或數(shù)組時(shí),這時(shí)候我們拷貝的只是一個(gè)棧內(nèi)存的指針。因此b對(duì)象在訪問(wèn)該屬性時(shí),會(huì)根據(jù)指針尋找...

    MangoGoing 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<