zoukankan      html  css  js  c++  java
  • js对象克隆

    大家都知道,js的对象是引用类型,如果直接var obj2 = obj,obj2和obj是共享同一个对象实体的,这往往不是我们想要的结果。

    官方并没有给出通用的对象克隆方法:

    我们给出以下几种写法:

    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对函数也是浅克隆处理)

    推荐阅读:https://juejin.im/post/5b235b726fb9a00e8a3e4e88

    ps:这里还有一些坑,无法克隆 Error 对象,无法克隆原型,无法克隆不可枚举的属性.... 不过这个深克隆已经可以覆盖百分之99的场景了!!

    2.JSON对象序列化方法

    深拷贝,但是有一大堆坑(推荐阅读:https://juejin.im/post/5abb55ee6fb9a028e33b7e0a):

    基础的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

  • 相关阅读:
    Linux命令学习Day1
    谈谈VAssitX Snippet
    Visual Studio sort函数出现“invalid operator<”原因分析
    网络打印机共享设置
    Notepad++使用总结
    Leetcode顺时钟旋转90度
    搭建Docker版gitlab私有云
    获取安卓APP设备上报信息
    中间件服务测试点整理
    Jenkins主从模式添加节点机
  • 原文地址:https://www.cnblogs.com/amiezhang/p/8023731.html
Copyright © 2011-2022 走看看