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

相关文章
相关标签/搜索