iT邦幫忙

0

Javascript 複製物件深拷貝觀念求解

想請問各位大大,在編輯json時會使用JSON.stringify()及JSON.parse() 將字串轉物件或事物漸轉字串進行操作,爬文後有人解說原因:透過先將物件轉成字串,再轉回物件,將傳參考的特性完全消滅。

JSON.parse(JSON.stringify(obj))

但是為甚麼透過這樣的轉換就能對一個物件進行深複製??
希望有大大可以替小弟解惑/images/emoticon/emoticon41.gif

froce iT邦大師 1 級 ‧ 2021-05-26 10:37:20 檢舉
你先把JSON變成文字,再解析回去,當然不會是同一個記憶體位置啊。
kekeke iT邦新手 4 級 ‧ 2021-05-26 10:59:40 檢舉
但他說 將傳參考的特性完全消滅。 如果沒參考 為甚麼KEY值不是空的呢?
froce iT邦大師 1 級 ‧ 2021-05-26 11:23:42 檢舉
看不懂你不懂的點是啥...

他重解析當然會是整個重跑一遍,包含重新分配記憶體位置及重新指派鍵值對,怎麼會有什麼key值是空的?

1 個回答

1
japhenchen
iT邦大師 1 級 ‧ 2021-05-26 11:02:09
最佳解答

深複製還是要用一點手段,我都不敢保證JSON.stringify不會弄丟資料

var a = { a: '1' };
console.log(a)

var b = deepClone(a);
console.log(b);

a.a = "2";
console.log(a);
console.log(b);



function deepClone(obj) {
    /*
     * Duplicates an object 
     */

    var ret = null;
    if (obj !== Object(obj)) { // primitive types
        return obj;
    }
    if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) { // string objecs
        ret = obj; // for ex: obj = new String("Spidergap")
    } else if (obj instanceof Date) { // date
        ret = new obj.constructor();
    } else
        ret = Object.create(obj.constructor.prototype);

    var prop = null;
    var allProps = Object.getOwnPropertyNames(obj); //gets non enumerables also


    var props = {};
    for (var i in allProps) {
        prop = allProps[i];
        props[prop] = false;
    }

    for (i in obj) {
        props[i] = i;
    }

    //now props contain both enums and non enums 
    var propDescriptor = null;
    var newPropVal = null; // value of the property in new object
    for (i in props) {
        prop = obj[i];
        propDescriptor = Object.getOwnPropertyDescriptor(obj, i);

        if (Array.isArray(prop)) { //not backward compatible
            prop = prop.slice(); // to copy the array
        } else
        if (prop instanceof Date == true) {
            prop = new prop.constructor();
        } else
        if (prop instanceof Object == true) {
            if (prop instanceof Function == true) { // function
                if (!Function.prototype.clone) {
                    Function.prototype.clone = function() {
                        var that = this;
                        var temp = function tmp() {
                            return that.apply(this, arguments);
                        };
                        for (var ky in this) {
                            temp[ky] = this[ky];
                        }
                        return temp;
                    }
                }
                prop = prop.clone();

            } else // normal object 
            {
                prop = deepClone(prop);
            }

        }

        newPropVal = {
            value: prop
        };
        if (propDescriptor) {
            /*
             * If property descriptors are there, they must be copied
             */
            newPropVal.enumerable = propDescriptor.enumerable;
            newPropVal.writable = propDescriptor.writable;

        }
        if (!ret.hasOwnProperty(i)) // when String or other predefined objects
            Object.defineProperty(ret, i, newPropVal); // non enumerable

    }
    return ret;
}
看更多先前的回應...收起先前的回應...
kekeke iT邦新手 4 級 ‧ 2021-05-26 11:08:21 檢舉

謝謝大大提供的方法~
想請問只要是重新解析的物件,就會新增一個記憶體位置,不知這樣的理解是不是對的?

用C++的角度來看,是產生一個新指標,然後把裡面的東西全部遞迴複製一遍

下面表演一下JSON.Stringify是如何弄丟東西的
要用到我提供的deepClone哦!


var a = {
    a: '1',
    firstName: 'xxxxx',
    lastName: '00000',
    fullName: function() {
        return this.firstName + " " + this.lastName;
    }
};

console.log(a.fullName());

var b = deepClone(a);
var c = JSON.parse(JSON.stringify(a));
console.log(b.fullName());
console.log(c.fullName());

debug結果
https://ithelp.ithome.com.tw/upload/images/20210526/20117954BHwP0tEGRc.jpg

你還敢JSON.Stringify ?

放在jsfiddle裡給大家玩
https://jsfiddle.net/japhenchen/Lc6z7fp4/3/
結論就是 fullName:function() 不會被JSONStringify到 c 去...

froce iT邦大師 1 級 ‧ 2021-05-26 11:47:45 檢舉

...放function就不是JSON了,只是javascript object而已。
JSON是交換格式,並沒有放function的格式。

題目是

JSON.parse(JSON.stringify(obj))

obj也不是JSON

JSON.stringify是個交換資料的好方法,但不能當做是"深層拷貝"的方法,樓主的意思是要把object複製到另一個

可以把JSON.Stringify看成是影印機,可以複印一份身份証,但卻不能當做正本使用

正本身份証右下角有個雷射貼紙,某個角度看會出現蝴蝶,這用複印的是無法出現,除非拿去給伊森杭特(不可能的任務)幫專業偽造,不然~~~(笑)

froce iT邦大師 1 級 ‧ 2021-05-26 12:53:05 檢舉

ㄜ...的確是我沒看清楚標題...

kekeke iT邦新手 4 級 ‧ 2021-05-27 08:48:57 檢舉

謝謝兩位大大的解說~~

我要發表回答

立即登入回答