js對象克隆

你們都知道,js的對象是引用類型,若是直接var obj2 = obj,obj2和obj是共享同一個對象實體的,這每每不是咱們想要的結果。es6

官方並無給出通用的對象克隆方法:數組

咱們給出如下幾種寫法:dom

1.通用對象克隆:異步

function clone(obj, hash = new WeakMap()) {
    // 解決循環引用
    if (hash.has(obj)) {
        return hash.get(obj)
    }
    let temp = null;
    if (obj instanceof Array) {
        // 特殊處理數組對象類型
        temp = []
        hash.set(obj, temp)
        obj.forEach(item => {
            temp.push(clone(item, hash));
        })
    } else if (obj instanceof RegExp) {
        // 特殊處理正則對象類型
        const { source, global, ignoreCase, multiline } = obj;
        let flags = '';
        if (global) flags += 'g';
        if (ignoreCase) flags += 'i';
        if (multiline) flags += 'm';
        temp = new RegExp(source, flags);
    } else if (obj instanceof Date) {
        // 特殊處理時間對象類型
        temp = new Date(obj.getTime());
    } else if (typeof obj === 'object') {
        // 處理普通對象類型
        // 以obj的原型爲原型,構造一個新對象
        temp = Object.create(obj.__proto__);
        hash.set(obj, temp)
    } else {
        temp = obj;
    }
    // 任何對象類型,都遍歷遞歸自身的屬性
    if (typeof obj === 'object') {
        for (let [key, val] of Object.entries(obj)) {
            temp[key] = clone(val, hash);
        }
    }
    return temp;
}

遇到數組對象類型、正則對象類型、時間對象類型、普通對象類型都須要有本身的特殊,最後他們都須要遍歷遞歸他們自身的屬性函數

原始類型(包括Symbol)純複製就能夠了工具

函數作的淺拷貝(由於若是拷貝函數,只能用eval這個危險的工具了,因此這裏函數僅做淺克隆,lodash的cloneDeep對函數也是淺克隆處理)post

推薦閱讀:http://www.javashuo.com/article/p-dkvzgydn-md.htmlspa

ps:這裏還有一些坑,沒法克隆 Error 對象,沒法克隆原型,沒法克隆不可枚舉的屬性.... 不過這個深克隆已經能夠覆蓋百分之99的場景了!!code

2.JSON對象序列化方法對象

深拷貝,可是有一大堆坑(推薦閱讀:http://www.javashuo.com/article/p-kopikzgj-hr.html):

基礎的5個大坑:

1. 函數不能拷貝

2. Symbol不能拷貝

4. undefined不能拷貝

5. 正則拷貝後變成普通對象

6. 循環引用的對象會報錯

7. 數組的屬性丟失

8. 數組裏面的undefined會變成null

9. 會拋棄對象的constructor

 。。。。估計還有不少我沒想到的

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

正常使用:

var obj = {a:1,b:2}  
var newObj = JSON.parse(JSON.stringify(obj)); 

3.dom元素的複製——cloneNode

let div = document.getElementById('box');
let box2 = div.cloneNode(true);

4.es6新方法——Object.assign

淺拷貝

var obj = {a:1,b:2}  
var newObj = Object.assign({}, obj); 

5. MessageChannel的方法

異步的深克隆,可是沒法克隆function 、Symbol

let obj = {a: 1,b: 2}

let {port1, port2} = new MessageChannel();
port2.onmessage = ev => console.log(ev.data)
port2.postMessage(obj)

 

總結:平常使用仍是推薦用lodash的cloneDeep

相關文章
相關標籤/搜索