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 ...
随机推荐
- Netty创建服务器与客户端
Netty 创建Server服务端 Netty创建全部都是实现自AbstractBootstrap.客户端的是Bootstrap,服务端的则是ServerBootstrap. 创建一个 HelloSe ...
- CSS RESET —— 浏览器样式重置
CSS Reset 1. CSS Reset为什么存在? 只要您的客户存在使用不同浏览器(ie,firefox,chrome等)的可能,那你就不得不从完美的理想状态回到现实,因为不同核心的浏览器对CS ...
- 0xe7f001f0!?NDK调试过程,无故抛出SIGSEGV。
arm调试过程,如果抛一个SIGSEGV,地址在 0xe7f001f0 附近,原因居然是因为我在调试.当我使用n指令跳到下一行代码时,往往变成了continue指令一样地执行.还不确定地抛出SIGSE ...
- .NET高级特性-Emit(1)
在这个大数据/云计算/人工智能研发普及的时代,Python的崛起以及Javascript的前后端的侵略,程序员与企业似乎越来越青睐动态语言所带来的便捷性与高效性,即使静态语言在性能,错误检查等方面的优 ...
- 🔥《手把手》系列基础篇之2-python+ selenium-打开和关闭浏览器(详细)
1. 简介 本节介绍如何初始化一个webdriver实例对象driver,然后打开和关闭firefox浏览器.要用selenium打开fiefox浏览器.首先需要去下载一个driver插件geckod ...
- Install gitlab
yum install -y curl policycoreutils-python openssh-server postfix wget wget https://mirrors.tuna.tsi ...
- PHP 模板引擎
PHP模板引擎的由来 ● 为了解决当时混合开发WEB应用出现的一系列问题:代码难维护,代码不可重用,程序员要求知识广等问题 ● 实现后端与前端不完全分离,开发与美工可以分工合作,提高效率 PHP模板引 ...
- 性能测试——记weblogic 连接池满无法链接故障诊断过程
记weblogic 连接池满无法链接故障诊断过程 前段时间公司负责建行的一个票据系统在,上线前几个分行试运行环境下,每天后台日志都会报oracle.jdbc.xa.OracleXAException, ...
- 2019-10-23:渗透测试,基础学习,DVWA,Medium和Hight级别sql注入
VWA的Medium和Hight级别sql注入 一,Medium级 服务端代码 <?php if( isset( $_POST[ 'Submit' ] ) ) { // Get inp ...
- 2019-9-9:渗透测试,基础学习,windows基础命令,笔记
windows系统基础命令学习 1,命令提示符界面进入方法 方法一: 某分区按住shift,右键单击选择在此处打开windows powershell,进入之后输入cmd 方法二:标题栏输入 方法三: ...