当前位置: 首页 > article >正文

Javascript高级—深浅拷贝

浅拷贝

浅拷贝是拷贝第一层的拷贝

使用Object.assign解决这个问题。

let a = {
  age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1

通过展开运算符 ... 来实现浅拷贝

let a = {
  age: 1
}
let b = {...a};
a.age = 2;
console.log(b.age)  // 1

深拷贝

简单的做法:JSON.parse(JSON.stringfy(obj))
但是该方法也是有局限性的:

  • 会忽略undefined
  • 会忽略symbol
  • 会忽略函数
  • 不能解决循环引用的对象 (会抱错)

如果你所需拷贝的对象含有内置类型并且不包含函数,可以使用 MessageChannel

自封装深拷贝
思路:

  1. 使用for-in遍历对象
  2. 因为for-in会遍历原型链上的属性,所以需要判断属性是否在原型链上,不是原型链才拷贝
  3. 判断属性值类型是原始类型和引用类型
  4. 原始类型直接赋值(注意null)
  5. 引用类型判断是对象还是数组,创建对应的空对象或空数组,递归调用函数,将值赋值进去
/**
 * 深度克隆
 * @param   origin 被拷贝的原对象
 * @param   target 拷贝出来的对象
 * @return         拷贝出来的对象
 */
function deepClone(origin, target) {
  target = target || {};
  for(let prop in origin) {   //使用 for-in
    if(origin.hasOwnProperty(prop)) { //是原型链上的
      if(typeof(origin[prop]) === 'object' && origin[prop] ) { //是对象
        // 先判断是不是数组
        if(origin[prop] instanceof Array) {
          target[prop] = [];
          deepClone(origin[prop], target[prop]);
        }
        target[prop] = {};
        deepClone(origin[prop], target[prop]);
      } 
      else {
        target[prop] = origin[prop];
      }
    }
  }
  return target;
}


//使用递归的方式实现数组、对象的深拷贝
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;
}

jQuery的extend方法实现

// 实现jQuery的extend函数

// v1:
function extend() {
    let i = 1;
    let len = arguments.length;
    let target = arguments[0];
    let options, copy;

    // 遍历第一个以后的所有参数
    for (; i < len; i++) {
        options = arguments[i];
        if (options != null) {
            for (let name in options) {
                copy = options[name];
                if (copy !== undefined) {
                    target[name] = copy;
                }
            }
        }
    }
    return target;
}


// TODO: 当前的这个版本不能深拷贝,只能覆盖(如果是对象属性的话)
// v2: 实现一个深度拷贝
function extend(){
    // 1. 默认是不进行深拷贝的
    let deep = false;
    let len = arguments.length;
    let i = 1;
    // 第一个参数如果不是一个bool的话,target默认就是第一个参数
    let target = arguments[0] || {};
    let options, src, copy;

    if (typeof target === 'boolean') {
        deep = target;
        target = arguments[i] || {};
        i++;
    }
    // 如果target不是对象的话,无法复制,设置为{}
    if (typeof target !== 'object') {
        target = {};
    }

    // 开始深拷贝
    for (; i < len; i++) {
        options = arguments[i];
        if (options != null) {
            for (let name in options) {
                // 开始准备源数据和目标数据
                src = target[name];
                copy = options[name];

                // 如果是对象的话,就深拷贝
                if (deep && copy && typeof copy === 'object') {
                    target[name] = extend(deep, src, copy);
                }
                else if (copy !== undefined) {
                    // 普通数据类型的话
                    target[name] = copy;
                }
            }
        }
    }

    return target;
}


// isPlainObject 函数来自于  [JavaScript专题之类型判断(下) ](https://github.com/mqyqingfeng/Blog/issues/30)
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;

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


function extend() {
    // 默认不进行深拷贝
    var deep = false;
    var name, options, src, copy, clone, copyIsArray;
    var length = arguments.length;
    // 记录要复制的对象的下标
    var i = 1;
    // 第一个参数不传布尔值的情况下,target 默认是第一个参数
    var target = arguments[0] || {};
    // 如果第一个参数是布尔值,第二个参数是 target
    if (typeof target == 'boolean') {
        deep = target;
        target = arguments[i] || {};
        i++;
    }
    // 如果target不是对象,我们是无法进行复制的,所以设为 {}
    if (typeof target !== "object" && !isFunction(target)) {
        target = {};
    }

    // 循环遍历要复制的对象们
    for (; i < length; i++) {
        // 获取当前对象
        options = arguments[i];
        // 要求不能为空 避免 extend(a,,b) 这种情况
        if (options != null) {
            for (name in options) {
                // 目标属性值
                src = target[name];
                // 要复制的对象的属性值
                copy = options[name];

                // 解决循环引用
                if (target === copy) {
                    continue;
                }

                // 要递归的对象必须是 plainObject 或者数组
                if (deep && copy && (isPlainObject(copy) ||
                    (copyIsArray = Array.isArray(copy)))) {
                    // 要复制的对象属性值类型需要与目标属性值相同
                    if (copyIsArray) {
                        copyIsArray = false;
                        clone = src && Array.isArray(src) ? src : [];

                    } else {
                        clone = src && isPlainObject(src) ? src : {};
                    }

                    target[name] = extend(deep, clone, copy);

                } else if (copy !== undefined) {
                    target[name] = copy;
                }
            }
        }
    }

    return target;
};

let obj1 = {
    a: 1,
    b: { b1: 1, b2: 2 }
};

let obj2 = {
    b: { b1: 3, b3: 4 , b4: 5},
    c: 3
};

let obj3 = {
    d: 4
}
console.log(extend(obj1, obj2, obj3));

<<<<<<< HEAD
console.log('---------------------');

var a = extend(true, [4, 5, 6, 7, 8, 9], [1, 2, 3]);
console.log(a) // ???

console.log('---------------------');
var obj11 = {
    value: {
        3: 1
    }
}

var obj22 = {
    value: [5, 6, 7],

}

var b = extend(true, obj11, obj22) // ???
var c = extend(true, obj22, obj11) // ???
console.log(b, c)



// 补充:深度克隆
function deepClone(obj) {
    let res = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (obj[key] && typeof obj[key] === 'object') {
                res[key] = deepClone(obj[key]);
            }
            else {
                res[key] = obj[key];
            }
        }
    }
    return res;
}




http://www.kler.cn/a/390447.html

相关文章:

  • request爬虫库的小坑
  • Springboot集成syslog+logstash收集日志到ES
  • MyBatisPlus 用法详解
  • 多叉树笔记
  • TensorRT基础知识
  • AI 扩展开发者思维方式:以 SQL 查询优化为例
  • Elasticsearch知识点汇总
  • 调用API进行验证码测试/python
  • 【vue3文件上传同时出现两个提示框,一个提示成功,一个提示失败,一个是用写死的,一个是接口返回的】
  • Android 图片保存
  • electron 中 contextBridge 作用
  • JVM 处理多线程并发执行
  • 什么是JVM实现
  • 电力巡检新利器:输电线路全景与云台变焦视频监控装置
  • 【算法-插入排序】基础知识,代码示例和应用场景
  • IDEA 如何手动创建spring boot工程
  • Day107:代码审计-PHP模型开发篇MVC层RCE执行文件对比法1day分析0day验证
  • .NET Core 应用程序如何在 Linux 中创建 Systemd 服务 ?
  • Vue3 - 小兔仙 - day2
  • 面试经典 150 题:121,125
  • 批量混剪矩阵发布助力短视频营销快速获客
  • 深度学习服务器租赁AutoDL
  • 使用git进行多人协作开发项目流程
  • Android WebSocket ping pong机制
  • MySQL如何利用索引优化ORDER BY排序语句
  • 【博主推荐】VUE开发常用技术点收集