• JavaScript 的 深拷贝和浅拷贝


    深拷贝和浅拷贝都是针对的引用类型,

    JS中的变量类型分为值类型(基本类型)和引用类型;

    对值类型进行复制操作会对值进行一份拷贝,而对引用类型赋值,则会对地址进行拷贝,最终两个变量指向同一份数据

    一、先来看看JS中的数据类型

    let x = 1;        //number类型
    let x = 0.1;     //number类型,JS不区分整数值和浮点数值
    
    let x = "hello world"; //由双引号内文本构成字符串
    let x = 'javascript';   //单引号内文本同样可以构成字符串
    
    let x = true;    // boolean 布尔类型
    
    let x = null;
    let x = undefined;  //null和undefined很相似,是特殊的类型

    JS 中数据分为两种类型:

    • 原始数据类型
      • number 
      • string
      • boolean
      • null
      • undefined
    • 对象数据类型
      • array 数组 特殊对象类型 
      • function 函数 特殊对象类型
      • object 对象

    还有 undefined 和 null,此处暂不讨论

    object对象需要注意的点:

    • 对象是可变的,即值是可以修改的
    • 对象的比较并非值得比较

    比如:var a = [], b = [];

         a == b;   //false,只有在引用相同(指向的地址相同)时,两个只才会相等

    由此可以延伸出 深拷贝和浅拷贝 的问题。

    =========================================================================

    我们的困惑:

    1. 看着相等,却又不等

     2. 想要不等,却又相等

     那么造成这样问题的原因在哪呢?

    > 对象的引用 

    > 引用只会对地址进行赋值, 所以

    1. 不同的变量 a 和 b,他们的地址不同,即使数据相同,本身也不会相等,这是造成困惑一的原因;

    2. 而变量 aa 和 bb 指向同一地址,当该地址的数据改变时,所有使用该地址的变量全部改变(同一数据),这是造成困惑二的原因

    达不到我们想要的效果,怎么办呢?

    二、引用(对象)数据类型的赋值和比较问题

    解决办法: 笨办法,也是唯一的方式,既然对象数据类型 是由基本数据类型组成的,而基本数据类型可以正常赋值、比较,那我们就把对象类型变成一个个的基本类型进行操作

    方法一: 遍历对象中的内容,一个一个的进行赋值,这样只进行一层拷贝的方式了,就是浅拷贝

    // 浅拷贝方法
    function shallowClone(source) {
        let target = {};
        for(leti in source) {
            if (source.hasOwnProperty(i)) {
                target[i] = source[i];
            }
        }
        return target;
    }

    方法二: 相对于一层拷贝的浅拷贝,无线层次的拷贝叫做 深拷贝

    // 简单深拷贝
    function clone(source) {
        let target = {};
        for(let i in source) {
            if (source.hasOwnProperty(i)) {
                if (typeof source[i] === 'object') {
                    target[i] = clone(source[i]); // 判断仍是对象,就进行递归
                } else {
                    target[i] = source[i];
                }
            }
        }
        return target;
    }

    上面 clone 方法 和 shallowClone 方法的 区别就是 多了 递归

    但是仍然有些问题需要注意:

    • 参数需要检验
    • 判断是否对象的逻辑不够严谨
    • 需要考虑数组的情况

    暂不细说,判断对象可以用此方法:

    // 更严谨的判断对象的方法
    function isObject(x) {
        return Object.prototype.toString.call(x) === '[object Object]';
    }

    当然我们也可以参考其他方法或使用插件

    比如: 简单粗暴的 JSON.parse(JSON.stringify(oldObj))

    比如: ES6的assign方法(浅拷贝)

    比如: 通过immutableJS实现深拷贝

    三、最后

    无论 浅拷贝,还是深拷贝 都会带来性能问题(平白的需要遍历,只是重新赋值)

    所以我们对象最好写的浅一点,精简一点。。。

    详细可以看这篇: https://yanhaijing.com/javascript/2018/10/10/clone-deep/

  • 相关阅读:
    计数问题
    自定义中间件
    中间件的数据流向
    模块化
    开发属于自己的包
    中间件
    java JDK环境变量配置
    uni-app 请求 uni.request封装使用
    uni-app 自定义 简单 底部tab
    vue 过滤器 filter 的使用
  • 原文地址:https://www.cnblogs.com/nangezi/p/11346971.html
Copyright © 2020-2023  润新知