Loading...
墨滴

墨林墨

2021/12/31  阅读:30  主题:默认主题

深浅拷贝

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。

浅拷贝:新对象赋值,只是取的旧对象栈中的值,也就是引用对象的值。浅拷贝出的所有变量都只是指向了一处而已,故会互相干涉。

深拷贝:会在堆里边开辟一个空间,存放自己的对象值。深拷贝出的所有变量都会开辟自己的空间来存放自己的值,因此指向也各不相同,故不会互相干涉。

1.数组的浅拷贝:只克隆第一级,其余的级别还是公用

//@1 slice
let cloneArr = arr.slice(0);
//@2 concat
cloneArr = arr.concat([]);
//@3 ...arr
cloneArr = [...arr];
//@4
cloneArr = [];
arr.forEach((item, index) => {
  cloneArr[index] = item;
});

2.对象的浅拷贝

let cloneObj = { ...obj };
cloneObj = Object.assign({}, obj);

3.深拷贝

先把原始对象变为JSON格式字符串,再把字符串变为对象「所涉及的内存,浏览器都会重新开辟一份全新的出来」

1. 使用递归的方式实现深拷贝

//使用递归的方式实现数组、对象的深拷贝
    function deepClone1(obj) {
      //判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
      var objClone = Array.isArray(obj) ? [] : {};
      //进行深拷贝的不能为空,并且是对象或者是
      if (obj && typeof obj === "object") {
        for (key in obj) {
          if (obj.hasOwnProperty(key)) {
            if (obj[key] && typeof obj[key] === "object") {
              objClone[key] = deepClone1(obj[key]);
            } else {
              objClone[key] = obj[key];
            }
          }
        }
      }
      return objClone;
    }

2. 通过 JSON 对象实现深拷贝

let arr = [10, 20, 'zhangsan', { name: 'zhangsan' }];
let cloneArr = JSON.parse(JSON.stringify(arr));
console.log(cloneArr === arr); //false
console.log(cloneArr[3] === arr[3]); //false

JSON.stringify的处理缺陷

  • 如果值是bigint则会报错 TypeError: Do not know how to serialize a BigInt
  • 如果值是 undefined/symbol/function 转换为字符串就没有了
  • 如果值是 正则/错误对象实例 直接变为“{}”
  • 如果值是 日期对象 变为字符串就回不来的
let obj = {
    name: 'zhangsan',
    age: 12,
    open: true,
    n: null,
    u: undefined,
    sy: Symbol(),
    big: 10n,
    cours: {
       chinese: 100,
       english: 50,
       math: 150
       },
       arr: [10, 20, 30],
       reg: /\d+/,
       err: new Error('错误信息'),
       fn: function () { },
       time: new Date()
     };
let cloneObj = JSON.parse(JSON.stringify(obj));
console.log(cloneObj);//看结果,会有问题

3. 通过jQuery的extend方法实现深拷贝

var array = [1,2,3,4];
var newArray = $.extend(true,[],array);

4.Lodash 或者 underscore 这些类库中都提供了深浅拷贝的办法

yarn add lodash

import _ from 'lodash'
var obj = {id:1,name:{a:'xx'},fn:function(){}};
var obj2 = _.cloneDeep(obj);
obj2.name.a = 'obj2';
console.log(obj,obj2)

5.自己封装深克隆

const isPlainObject = function isPlainObject(obj) {
            let proto, Ctor;
            if (!obj || Object.prototype.toString.call(obj) !== "[object Object]"return false;
            proto = Object.getPrototypeOf(obj);
            if (!proto) return true;
            Ctor = proto.hasOwnProperty('constructor') && proto.constructor;
            return typeof Ctor === "function" && Ctor === Object;
        };

 const cloneDeep = function cloneDeep(obj, st = new Set()) {
            // 为了防止套娃
            if (st.has(obj)) return obj;
            st.add(obj);

            // 原始值类型的克隆:无需克隆,传啥返啥
            if (obj == null || !/^(object|function)$/i.test(typeof obj)) return obj;

            // 特殊对象值的处理
            let isArray = Array.isArray(obj),
                isObject = isPlainObject(obj),
                type = /^\[object (\w+)\]$/.exec(Object.prototype.toString.call(obj))[1].toLowerCase(),
                ctor = obj.constructor;
            if (type === "date" || type === "regexp"return new ctor(obj);
            if (type === "error"return new ctor(obj.message);
            if (type === "function"return function (...params) {
                return obj.call(this, ...params);
            };
            if (!isArray && !isObject) return obj;

            // 数组和纯粹对象的处理
            let clone = new ctor(),
                keys = Object.keys(obj).concat(Object.getOwnPropertySymbols(obj));
            keys.forEach(key => {
                // 基于递归实现深拷贝
                clone[key] = cloneDeep(obj[key], st);
            });
            return clone;
        };

let obj = {
            name: 'zhangsan',
            age: 12,
            cours: {
                chinese: 100,
                english: 50,
                math: 150
            },
            arr: [10, 20, 30],
            reg: /\d+/,
            err: new Error('错误信息'),
            fn: function () { },
            time: new Date()
        };
        obj.obj = obj; //套娃
        let clone = cloneDeep(obj);

6.使用

vue中使用

react中使用

墨林墨

2021/12/31  阅读:30  主题:默认主题

作者介绍

墨林墨