浅拷贝

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

使用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.stringify(obj))

但是该方法也是有局限性的:

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

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

自封装深拷贝

思路:

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

深拷贝 - BFS

// 如果是对象/数组,返回一个空的对象/数组,
// 都不是的话直接返回原对象
function getEmptyArrOrObj(item) {
let itemType = Object.prototype.toString.call(item)
if(itemType === '[object Array]') {
return []
}
if(itemType === '[object Object]') {
return {}
}
return item
} function deepCopyBFS(origin) {
const queue = []
const map = new Map() // 记录出现过的对象,处理环 let target = getEmptyArrOrObj(origin) if(target !== origin) {
// 说明origin是一个对象或数组,需要拷贝子代
queue.push([origin, target]);
map.set(origin, target)
} while(queue.length) { let [ori, tar] = queue.shift(); // 出队 for(let key in ori) {
if(ori.hasOwnProperty(key)) { // 不在原型上 if(map.get(ori[key])) { // 处理环
tar[key] = map.get(ori[key])
continue
} tar[key] = getEmptyArrOrObj(ori[key]);
if(tar[key] !== ori[key]) {
queue.push(ori[key], tar[key])
map.set(ori[key], tar[key])
}
}
}
} return target
}

深拷贝 - DFS

function deepCopyDFS(origin){
let stack = [];
let map = new Map(); // 记录出现过的对象,用于处理环 let target = getEmptyArrOrObj(origin);
if(target !== origin){
stack.push([origin, target]);
map.set(origin, target);
} while(stack.length){
let [ori, tar] = stack.pop();
for(let key in ori){
if(ori.hasOwnProperty(key)) { // 不在原型上
// 处理环状
if(map.get(ori[key])){
tar[key] = map.get(ori[key]);
continue;
} tar[key] = getEmptyArrOrObj(ori[key]);
if(tar[key] !== ori[key]){
stack.push([ori[key], tar[key]]);
map.set(ori[key], tar[key]);
}
}
}
} return target;
}

测试上面的两个 deepCopy

JS中的深拷贝和浅拷贝的更多相关文章

  1. js 中的深拷贝与浅拷贝

    在面试中经常会问到js的深拷贝和浅拷贝,也常常让我们手写,下面我们彻底搞懂js的深拷贝与浅拷贝. 在js中 Array 和 Object  这种引用类型的值,当把一个变量赋值给另一个变量时,这个值得副 ...

  2. js中的深拷贝与浅拷贝

    对象的深拷贝于浅拷贝 对于基本类型,浅拷贝过程就是对值的复制,这个过程会开辟出一个新的内存空间,将值复制到新的内存空间.而对于引用类型来书,浅拷贝过程就是对指针的复制,这个过程并没有开辟新的堆内存空间 ...

  3. js 中的 深拷贝与浅拷贝

    js在平时的项目中,赋值操作是最多的:比如说: var person1 = { name:"张三", age:18, sex:"male", height:18 ...

  4. js中的深拷贝和浅拷贝2

    所谓 深浅拷贝: 对于仅仅是复制了引用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响,为 浅拷贝. 而如果是在堆中重新分配内存,拥有不同的地址,但是值是一 ...

  5. JS对象复制(深拷贝、浅拷贝)

    如何在 JS 中复制对象 在本文中,我们将从浅拷贝(shallow copy)和深拷贝(deep copy)两个方面,介绍多种 JS 中复制对象的方法. 在开始之前,有一些基础知识值得一提:Javas ...

  6. javascript中的深拷贝与浅拷贝

    javascript中的深拷贝与浅拷贝 基础概念 在了解深拷贝与浅拷贝的时候需要先了解一些基础知识 核心知识点之 堆与栈 栈(stack)为自动分配的内存空间,它由系统自动释放: 堆(heap)则是动 ...

  7. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

  8. C语言中的深拷贝和浅拷贝

    //C语言中的深拷贝和浅拷贝 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #inc ...

  9. 浅谈Java中的深拷贝和浅拷贝

    转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...

随机推荐

  1. 朱辉(茶水): Linux Kernel iowait 时间的代码原理

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 朱辉(茶水) 来源: 微信公众号linux阅码场(id: linuxdev) 作者介绍 朱辉,个人主页 htt ...

  2. ubuntu触摸板双指滑动,页面滚动方向

    setting——mouse & Touchpad——Natural scrolling 跟我的另一台本子一样了-

  3. 【故障公告】数据库服务器 CPU 近 100% 引发的故障(源于 .NET Core 3.0 的一个 bug)

    非常抱歉,这次故障给您带来麻烦了,请您谅解. 今天早上 10:54 左右,我们所使用的数据库服务(阿里云 RDS 实例 SQL Server 2016 标准版)CPU 突然飙升至 90% 以上,应用日 ...

  4. 【目标检测实战】目标检测实战之一--手把手教你LMDB格式数据集制作!

    文章目录 1 目标检测简介 2 lmdb数据制作 2.1 VOC数据制作 2.2 lmdb文件生成 lmdb格式的数据是在使用caffe进行目标检测或分类时,使用的一种数据格式.这里我主要以目标检测为 ...

  5. 勾股数专题-SCAU-1079 三角形-18203 神奇的勾股数(原创)

    勾股数专题-SCAU-1079 三角形-18203 神奇的勾股数(原创) 大部分的勾股数的题目很多人都是用for来便利,然后判断是不是平方数什么什么的,这样做的时候要对变量类型和很多细节都是要掌握好的 ...

  6. 18个awk的经典实战案例

    介绍 这些案例是我收集起来的,大多都是我自己遇到过的,有些比较经典,有些比较具有代表性. 这些awk案例我也录了相关视频的讲解awk 18个经典实战案例精讲,欢迎大家去瞅瞅. 插入几个新字段 在&qu ...

  7. AppBoxFuture: 集成第三方Sql数据库

      框架设计之初是不准备支持第三方数据库的,但最近几个朋友都提到需要将旧的基于传统Sql数据库的应用迁移到框架内,主要是考虑到一方面目前框架内置的分布式数据库尚未完善,另一方面是希望能逐步迭代旧应用替 ...

  8. go中的关键字-go(下)

    1. goroutine源码分析 1.1 初始化 go程序的启动流程分为四步 call osinit, 这里就是设置了全局变量ncpu = cpu核心数量 call schedinit make &a ...

  9. day20191104笔记

    MyBatis笔记: 一.MyBatis半自动ORM映射框架, 将数据库中的数据和程序中的数据进行自动映射的前提条件 1. 数据库中的字段必须和程序中的属性保持一致 2. 程序中属性的数据类型必须是基 ...

  10. P1035 级数求和

    题目描述 已知:S_n= 1+1/2+1/3+…+1/nSn​=1+1/2+1/3+…+1/n.显然对于任意一个整数KK,当nn足够大的时候,S_nSn​大于KK. 现给出一个整数KK(1 \le k ...