zoukankan      html  css  js  c++  java
  • 深拷贝和浅拷贝

    浅拷贝: 对象只被克隆了一个引用或者只会被克隆最外部的一层,更深层的对象还是通过引用指向同一块堆内存。

    1. Object.assign()

     1 let p1= { 
     2     name: 'Tom' ,
     3     children: [{
     4         name: 'A'
     5     }]
     6 };
     7 let p2 = Object.assign({}, p1);
     8 p1.name = 'Tim';
     9 console.log(p2.name); // Tom
    10 p1.children[0].name = 'B';
    11 console.log(p2.children[0].name); // B

    2. 展开运算符 ...

    1 let p1 = {
    2     name: 'Tom',
    3     children: [{
    4         name: 'A'
    5     }]
    6 };
    7 let p2 = { ...p1 };
    8 p1.name = 'Tim';
    9 console.log(p1.name); // Tom

    3. 自己编写一个函数

    1 function shallowClone(obj) {
    2     const result = {};
    3     for (let key in obj) {
    4         result[key] = obj[key];
    5     }
    6     return obj;
    7 }

    深拷贝:不光解决了第一层的问题,还递归拷贝了目标对象的所有属性。

    1. JSON.parse(JSON.strigify())

     1 function Person(name) { 
     2     this.name = name;
     3 }
     4 const p = new Person('Tom');
     5 
     6 const oldObj = {
     7     a: function() { console.log('hi');},
     8     b: new Array(1),
     9     c: new RegExp('ab+c', 'i'),
    10     d: p,
    11     e: Symbol('a'),
    12     f: undefined
    13 };
    14 
    15 const newObj = JSON.parse(JSON.stringify(oldObj));
    16 
    17 console.log(oldObj);
    18 //{ 
    19     a: ƒ (),
    20     b: [empty],
    21     c: /ab+c/i,
    22     d: Person {name: "Tom"},
    23     e: Symbol(male),
    24     f: undefined
    25 }
    26 console.log(newObj);
    27 //{
    28     b: [null],
    29     c: {},
    30     d: {name: "Tom"}
    31 }

    缺点:

    • 无法实现对函数、undefined、regexp、symbol等类型克隆
    • 会抛弃对象的constructor,所有的构造函数都会指向object
    • 对象有循环引用会报错

    2. 简单的深拷贝(不考虑函数、Date、RegExp等类型)

    1 const deepClone = (obj) => {
    2     if (obj === null || typeof obj !== 'object') return obj;
    3     let cloneObj = Array.isArray(obj) ? [] : {};
    4     for(let key in obj) {
    5         if (!obj.hasOwnProperty(key)) return;
    6         cloneObj[key] = obj[key] !== null && typeof obj === 'object' ? deepClone(obj[key]) : obj[key];
    7     }
    8     return cloneObj;
    9 }

    3. 考虑部分类型的简易版深拷贝,推荐使用 lodash 的深拷贝函数。

     1 const isType = (obj, type) => Object.prototype.toString.call(obj).slice(8, -1) === type;
     2 
     3 // 可用es6的flags替换(ie不支持)
     4 const getRegExp = re => {
     5     var result = '';
     6     if (re.global) result += 'g';
     7     if (re.ignoreCase) result += 'I';
     8     if (re.multiline) result += 'm';
     9     return result;
    10 }
    11 
    12 const deepClone = (obj) => {
    13     const oldList = [];
    14     const newList = [];
    15     const _clone = (parent) => {
    16         if (parent === null || typeof parent !== 'object') return parent;
    17         let result;
    18         if (isType(parent, 'Array')) {
    19             result = [];
    20         } else if (isType(parent, 'RegExp')) {
    21             result = new RegExp(parent.source, getRegExp(parent)); // 等同于 parent.flags
    22             if (parent.lastIndex) resut.lastIndex = parent.lastIndex;
    23         } else if (isType(parent, 'Date')) {
    24             result = new Date(parent.getTime());
    25         } else {
    26             result = Object.create(Object.getPrototypeOf(parent));
    27         }
    28         // 处理循环引用
    29         const index = oldList.indexOf(parent);
    30         if (index !== -1) {
    31             return newList[index];
    32         }
    33         oldList.push(parent);
    34         newList.push(result);
    35 
    36         for (let attr in parent) {
    37             // 递归调用
    38             result[attr] = _clone(parent[attr]);
    39         }
    40         return result;
    41     };
    42     return _clone(obj);
    43 }

    4. MessageChannel

     1 // 若所需拷贝的对象含有内置类型并且不包含函数,可以使用MessageChannel
     2 
     3 const structuralClone = obj => {
     4     return new Promise(resolve => {
     5         const {port1, port2} = new MessageChannel();
     6         port2.onmessage = ev => resolve(ev.data);
     7         port1.postMessage(obj);
     8     });
     9 };
    10 
    11 const test = async () => {
    12     const clone = await structuralClone(obj);
    13     console.log(clone);
    14 };
    15 test();
  • 相关阅读:
    印度出差之一
    印度出差疯狂的鸡翅
    GET和POST两种基本请求方法的区别
    对sleep和wait的理解
    Jquery 鼠标滑过时改变元素透明度的动画效果
    记忆里的科比
    New Features Summary Of Sybase® PowerDesigner® 15.0 For Windows[PD15新功能特征摘要]
    WF工作流接口规范
    Foxmail安装文件夹的整体转移(收集)
    c# vs2005 多线程中调用窗体控件 (摘)
  • 原文地址:https://www.cnblogs.com/gromimiss/p/10369057.html
Copyright © 2011-2022 走看看