Sky
HOME
HOME
  • 前端笔记

    • CSS

      • 盒子模型
      • 屏幕单位
      • CSS 性能优化
    • JavaScript

      • Methods

        • Scheduler
        • Deep Clone
        • Curry
        • Calculation Function
        • debounce & throttle
      • Function bind
      • Array reduce
      • cross domain
      • event loop
      • ajax
      • event
      • context
      • inheritance
      • prototype
    • HTML

      • html render
      • forbidden <a>
      • <meta>
      • <script>
    • uni-app

      • scroll table

Deep Clone | 深拷贝

所有元素或属性均完全克隆,并于原引用类型完全独立,即,在后面修改对象的属性的时候,原对象不会被修改。

在 JavaScript 中复制一个对象几乎都是浅拷贝而不是深拷贝。

浅拷贝

浅拷贝只是复制了对象的引用,而不是对象本身。


const me = {
  name: 'ddd',
  age: 21,
  girlFriend: {
      name: 'bbb',
      age: 81
  }
};

const meCopy = {...me};

me.age = 22;
console.log(me.age);// 21

me.girlFriend.age = 82;
console.log(me.girlFriend.age);// 82

有七种原始数据类型:string、number、bigint、boolean、undefined、symbol 和 null。

深拷贝

考虑几个因素:

  • 传入的对象是使用对象字面量{}创建的对象还是由构造函数生成的对象
  • 如果对象是由构造函数创建出来的,那么是否要拷贝原型链上的属性
  • 如果要拷贝原型链上的属性,那么如果原型链上存在多个同名的属性,保留哪个
  • 如果对象中存在循环引用的情况,如何处理

JSON

使用简单,且兼容性好

它能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。


let _clone = JSON.parse(JSON.stringify(obj));

弊端:

  • obj 对象存在循环引用,那么该方法会报错
  • 对象存在 Date 对象,该方法会将其转化成字符串
  • obj 对象中存在 Set、Map、正则、Error 对象,该方法会将其转成空对象字面量 { } ,如果存在 undefined,该方法会直接忽略

Lodash.cloneDeep

兼容性好,功能强大,对于 Function 类型不会报错

注意处理 tree-shaking

  • lodash按需引入
  • Lodash: tree shaking
    /**
     * 
     * @param {*} value 要深拷贝的值
     * @returns 返回深拷贝后的值
     * 
    */
    _.cloneDeep(value)

structuredClone

浏览器原生支持, 兼容性问题


    /**
     * @param {*} value 被克隆的对象。可以是任何结构化克隆支持的类型。  
     * @param {*} options 是一个可转移对象的数组,里面的 值 并没有被克隆,而是被转移到被拷贝对象上。
     * @returns 返回一个与被克隆对象结构相同的对象。
     * 
    */

    structuredClone(value)
    structuredClone(value, { transfer })

polyfill

基本实现


    function deepClone(obj) {
        if (obj === null) return null;
        if (typeof obj !== 'object') return obj;
        let newObj = Array.isArray(obj) ? [] : {};
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) { //不遍历其原型链上的属性
                let val = obj[key];
                newObj[key] = typeof val === 'object' ? deepClone(val) : val; 
            }
        }
        return newObj;
    }

参考

  1. JS 原生的深拷贝来啦——structuredClone
  2. JavaScript如何实现深拷贝
最近更新: 2023/12/6 16:02
Contributors: liujw155@outlook.com
Prev
Scheduler
Next
Curry