小tips:使用JSON.parse(JSON.stringify(object))實現深拷貝的局限及擴展


使用JSON.parse(JSON.stringify(object))實現深拷貝局限

大部分情況我們都可以使用JSON.parse(JSON.stringify(object))來實現深拷貝,但該方法也有局限性,如下:

  • 會忽略 undefined
  • 會忽略 symbol
  • 不能序列化函數
  • 不能解決循環引用的對象

例如:

let a = {
  age: undefined,
  sex: Symbol('male'),
  jobs: function() {},
  name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}

 借用 MessageChannel 實現深拷貝

MessageChannel API允許我們創建一個新的消息通道,並通過它的兩個MessagePort屬性發送數據。

var channel = new MessageChannel();

這樣就創建了一個管道。

實例屬性:

channel.port1
channel.port2

獲取實例的兩個端口,注意的是,兩個端口都是只讀的。

簡單來說,MessageChannel創建了一個通信的管道,這個管道有兩個端口,每個端口都可以通過postMessage發送數據,而一個端口只要綁定了onmessage回調方法,就可以接收從另一個端口傳過來的數據。

一個簡單的例子:

var channel = new MessageChannel();
var port1 = channel.port1;
var port2 = channel.port2;
port1.onmessage = function(event) {
    console.log("port1收到來自port2的數據:" + event.data);
}
port2.onmessage = function(event) {
    console.log("port2收到來自port1的數據:" + event.data);
}

port1.postMessage("發送給port2");
port2.postMessage("發送給port1");

而通過 postMessage() 方法傳輸的 message 參數是深拷貝的。

function deepClone(val) {
    return new Promise((resolve,reject) => {
        const {port1,port2} = new MessageChannel();
        port2.onmessage = e => resolve(e.data);
        port1.postMessage(val);
    })
}

let obj = {
  age: undefined,
  name: 'yck',
  c: {
      d: true
  }
}
obj.c.e = obj.c; // 循環引用

// 注意該方法是異步
async function test() {
    const clone = await deepClone(obj);
    console.log(clone) // {age: undefined, name: "yck", c: {…}}
}
test()

但這個深拷貝只能解決 undefined 和循環引用對象的問題,對於 Symbol 和 function 依然束手無策。

詳細可參考:《MessageChannel 消息通道》

簡易版的深拷貝

var extendCopy = (function f(p,c){
    var c = c || {};
    for (var i in p) {
        if(typeof p[i] === 'object'){
            c[i] = (p[i] instanceof Array) ? [] : {};
            f(p[i],c[i]);
        }else{
             c[i] = p[i];
        } 
    }
    return c;
});

詳細可參考:《小tips:JS之淺拷貝與深拷貝》

lodash 的深拷貝函數

語法:

_.cloneDeep(value)

示例:

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

地址:https://lodash.com/docs/4.17.15#cloneDeep


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM