JS中的深拷贝和浅拷贝
浅拷贝
浅拷贝是拷贝第一层的拷贝
使用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
自封装深拷贝
思路:
- 使用for-in遍历对象
- 因为for-in会遍历原型链上的属性,所以需要判断属性是否在原型链上,不是原型链才拷贝
- 判断属性值类型是原始类型和引用类型
- 原始类型直接赋值(注意null)
- 引用类型判断是对象还是数组,创建对应的空对象或空数组,递归调用函数,将值赋值进去
/**
* 深度克隆
* @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;
}
JS中的深拷贝和浅拷贝的更多相关文章
- js 中的深拷贝与浅拷贝
在面试中经常会问到js的深拷贝和浅拷贝,也常常让我们手写,下面我们彻底搞懂js的深拷贝与浅拷贝. 在js中 Array 和 Object 这种引用类型的值,当把一个变量赋值给另一个变量时,这个值得副 ...
- js中的深拷贝与浅拷贝
对象的深拷贝于浅拷贝 对于基本类型,浅拷贝过程就是对值的复制,这个过程会开辟出一个新的内存空间,将值复制到新的内存空间.而对于引用类型来书,浅拷贝过程就是对指针的复制,这个过程并没有开辟新的堆内存空间 ...
- js 中的 深拷贝与浅拷贝
js在平时的项目中,赋值操作是最多的:比如说: var person1 = { name:"张三", age:18, sex:"male", height:18 ...
- js中的深拷贝和浅拷贝2
所谓 深浅拷贝: 对于仅仅是复制了引用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响,为 浅拷贝. 而如果是在堆中重新分配内存,拥有不同的地址,但是值是一 ...
- JS对象复制(深拷贝、浅拷贝)
如何在 JS 中复制对象 在本文中,我们将从浅拷贝(shallow copy)和深拷贝(deep copy)两个方面,介绍多种 JS 中复制对象的方法. 在开始之前,有一些基础知识值得一提:Javas ...
- javascript中的深拷贝与浅拷贝
javascript中的深拷贝与浅拷贝 基础概念 在了解深拷贝与浅拷贝的时候需要先了解一些基础知识 核心知识点之 堆与栈 栈(stack)为自动分配的内存空间,它由系统自动释放: 堆(heap)则是动 ...
- 浅谈Java中的深拷贝和浅拷贝(转载)
浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...
- C语言中的深拷贝和浅拷贝
//C语言中的深拷贝和浅拷贝 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #inc ...
- 浅谈Java中的深拷贝和浅拷贝
转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...
随机推荐
- 如何使用Sping Data JPA更新局部字段
问题描述 在更新数据时,有时候我们只需要更新一部分字段,其他字段保持不变.Spring Data JPA并未提供现成的接口,直接使用save()更新会导致其他字段被Null覆盖掉. 解决办法 通常有两 ...
- 逆向libbaiduprotect(三)- 移植python操作dalvik虚拟机c++函数,配合gdb控制程序运行流程
python编译移植到测试机,并且移植ctypes模块.利用ctypes代替c程序,利用dalvik内部c++函数,在运行过程中手动命令操控dalvik虚拟机,并结合gdb进行调试.绕过zygote和 ...
- (四十四)golang--协程(goroutine)和管道(channel)相结合实例
统计1-8000之间的素数. 整体框架: 说明:有五个协程,三个管道.其中一个协程用于写入数字到intChan管道中,另外四个用于取出intChan管道中的数字并判断是否是素数,然后将素数写入到pri ...
- python--BMI
#bmi height,weight = eval(input("请输入身高(m) 体重(kg),以逗号隔开\n")) bmi = weight/pow(weight,2) pri ...
- C语言基础 -- 变量
常用变量类型 地址 小端 低地址保存低位,高地址保存高位 常用于 PC(复杂指令集) 大端 低地址保存高位,高地址保存低位 常用于 ARM/手机/网络(精简指令集)
- Git之GitFlow工作流
一. GitFlow 介绍 1.1 什么是 GitFlow GitFlow 是一种 Git 工作流,它是团队成员遵守的一种代码管理方案 . 1.2 GitFlow 常用分支说明 分支名称 分支说明 P ...
- opencv简介以及环境搭建
1.opencv简介 opencv:全称:Open Source Computer Vision Library 是一个跨平台的计算机视觉库 可用于开发实时的图像处理.计算机视觉以及模式识别程序 应用 ...
- 01 jQuery配置、jQuery语法结构、jQuery对象与DOM对象的互相转换
配置jQuery环境 下载jQuery 官网:jquery.com 学习或开发建议选择未压缩版,便于学习,发布建议选择压缩版,便于用户极速体验(点击下载若出现的是代码页 面,Ctrl+A全选复制 ...
- java 抽象类和接口整理
java中定义一些不含方法体的方法,方法体的实现交给该类的子类根据自己的具体情况去实现,这样的方法就是abstract修饰的抽象方法,包含抽象方法的类叫抽象类,用abstract修饰 抽象方法: ab ...
- 2019-2020-8 20199317 《Linux内核原理与分析》 第八周作业
第7章 可执行程序工作原理 1 ELF目标文件格式 1.1 ELF概述 “目标文件”,是指编译器生成的文件.“目标”指目标平台目标文件一般也叫作ABI(Application Bi ...