在JavaScript分为两种原始值和引用值类型,原始值之间的复制是值对值得复制,而引用类型则是引用对引用的复制;

// 原始值的复制;
let num1 = 1;
let num2 = num1;
num2++;
console.log(num1,num2); // 1,2
// 引用类型的复制;
let joe = {
name:"joe",
age:20
}

let john = joe;
john.name = 'john';

console.log(john === joe,joe.name); // true john

如你所见,当我们把joe 赋值给john时实际上并没有完全复制一个新的,就好像是下面这样:

图片来自 “现代JavaScript教程” 网站;

Object.assign(target,arg1,arg2,...)方法用于将第二个参数及以后所有的对象都合并到第一个对象中,并返回第一个对象;

let user = {
name:"申屠肆",
hobbies:{
first:'JavaScript',
second:'Node'
}
} let user_copy = Object.assign({job:'Web开发'},user,);
user_copy.name = '谢必安';
user_copy.hobbies['third'] = 'Python'; console.log(user_copy.name,user.name);
console.log(user_copy.hobbies,user.hobbies); //控制台 谢必安 申屠肆
{ first: 'JavaScript', second: 'Node', third: 'Python' } { first: 'JavaScript', second: 'Node', third: 'Python' }

虽然Object.assign可以达到我们想要的效果,但是,可以发现,如果合并的对象的某个键对应的值仍然是对象,则还是会存下对象的引用;

接下来,让我们探寻更进一步的方案

// 采用递归 + JSON对象的方法 来完成深度复制

function deep_clone(source,target = {}) {
for(let key in source) { if(source[key].constructor === Object) {
target[key] = deep_clone(source[key])
}else if (source[key].constructor === Array) {
target[key] = JSON.parse(JSON.stringify(source[key]))
} else {
target[key] = source[key];
} }
return target;
}

让我们来试一下

var ball = {
name:'足球',
shape:{
text:'圆形',
size:40
},
abc:[1],
def:[{user:'谢绝'}]
} function deep_clone(source,target = {}) {
for(let key in source) { if(source[key].constructor === Object) {
target[key] = deep_clone(source[key])
}else if (source[key].constructor === Array) {
target[key] = JSON.parse(JSON.stringify(source[key]))
} else {
target[key] = source[key];
} }
return target;
}

var ball_copy = deep_clone(ball);
ball_copy.shape.text="方形";
ball_copy.abc.push(2);
ball_copy.def[0].user = "谢绝-copy";
console.log(ball_copy,ball);
// 控制台打印
{
name: '足球',
shape: { text: '方形', size: 40 },
abc: [ 1, 2 ],
def: [ { user: '谢绝-copy' } ]
} {
name: '足球',
shape: { text: '圆形', size: 40 },
abc: [ 1 ],
def: [ { user: '谢绝' } ]
}

使用该方法需要注意的是,不能有“环形结构”

推荐阅读:《现代JavaScript教程》

JavaScript中的对象引用和复制的更多相关文章

  1. JavaScript 中的对象引用

    ECMAScirpt 变量有两种不同的数据类型:基本类型,引用类型.也有其他的叫法,比如原始类型和对象类型,拥有方法的类型和不能拥有方法的类型,还可以分为可变类型和不可变类型,其实这些叫法都是依据这两 ...

  2. JavaScript 中的对象深度复制(Object Deep Clone)

    JavaScript中并没有直接提供对象复制(Object Clone)的方法. JavaScript中的赋值,其实并不是复制对象,而是类似`c/c++`中的引用(或指针),因此下面的代码中改变对象b ...

  3. javascript中的对象,原型,原型链和面向对象

    一.javascript中的属性.方法 1.首先,关于javascript中的函数/“方法”,说明两点: 1)如果访问的对象属性是一个函数,有些开发者容易认为该函数属于这个对象,因此把“属性访问”叫做 ...

  4. javascript中关于深复制与浅复制的问题

    在javascript中,变量的类型分为基本类型和引用类型. 对于基本类型的变量来说,值的复制以及作为函数参数实参传递的过程都是值的复制传递,换句话说,是会在内存中开辟出一个新空间用于存放新的值的.这 ...

  5. 【转】JavaScript中的对象复制(Object Clone)

    JavaScript中并没有直接提供对象复制(Object Clone)的方法.因此下面的代码中改变对象b的时候,也就改变了对象a. a = {k1:1, k2:2, k3:3}; b = a; b. ...

  6. Javascript中的一种深复制实现

    在javascript中,所有的object变量之间的赋值都是传地址的,可能有同学会问哪些是object对象.举例子来说明可能会比较好: typeof(true) //"boolean&qu ...

  7. 深度解析javascript中的浅复制和深复制

    原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...

  8. 对 JavaScript 中的5种主要的数据类型进行值复制

    定义一个函数 clone(),可以对 JavaScript 中的5种主要的数据类型(包括 Number.String.Object.Array.Boolean)进行值复制 使用 typeof 判断值得 ...

  9. javascript 中的深复制 和 其实现方法

    首先,我们需要明白什么是深复制(侧重指对象方面)? 在javascript中,复制分为浅复制和深复制,个人理解,浅复制就是直接将引用复制,复制前后的两个对象指向同一个内存地址,对其中一个进行操作,另外 ...

随机推荐

  1. 一种获取context中keys和values的高效方法 | golang

    我们知道,在 golang 中的 context 是一个非常重要的包,保存了代码活动的上下文.我们经常使用 WithValue() 这个方法,来往 context 中 传递一些 key value 数 ...

  2. Py装饰器

    装饰器: 1.定义,什么是装饰器 装饰器本质是一个函数,它是为了给其他函数添加附加功能 2.装饰器的两个原则 原则1   不修改被修饰函数的源代码原则2   不修改被修饰函数的调用方式 3.首先来看一 ...

  3. 基于final shell的linux命令

    final shell操作教程: 1.查看API实时日志:cd ../../data/log/api tail -100f anyAPI-server.log2.关闭日志:control+c3.恢复实 ...

  4. 【Redis 分布式锁】(1)一把简单的“锁”

    原文链接:https://www.changxuan.top/?p=1230 在单体架构向分布式集群架构演进的过程中,项目中必不可少的一个功能组件就是分布式锁.在开发团队有技术积累的情况下,做为团队的 ...

  5. java创建线程的多种方式

    java创建线程的四种方式 1.继承 Thread 类 通过继承 Thread 类,并重写它的 run 方法,我们就可以创建一个线程. 首先定义一个类来继承 Thread 类,重写 run 方法. 然 ...

  6. 在plsql/developer的命令窗口执行sql脚本

    在plsql/developer的命令窗口执行sql脚本的命令是@+路径. 命令窗口,如下: 1.在指定位置创建.sql文件 2-1.输入@,点击回车,选择.sql文件 2-2.或者@加路径

  7. 引入 Gateway 网关,这些坑一定要学会避开!!!

    Spring cloud gateway是替代zuul的网关产品,基于Spring 5.Spring boot 2.0以上.Reactor, 提供任意的路由匹配和断言.过滤功能.上一篇文章谈了一下Ga ...

  8. Javascript关键字,条件语句,函数及函数相关知识

    关键字 条件语句 作用域 回调 关键字 根据规定,关键字是保留的,不能用作变量名或函数名. 下面是一些ECMAScript关键字的完整列表. break ,case,catch,continue,de ...

  9. Tomcat 核心组件 Connector

    Connector是Tomcat的连接器,其主要任务是负责处理浏览器发送过来的请求,并创建一个Request和Response的对象用于和浏览器交换数据,然后产生一个线程用于处理请求,Connecto ...

  10. java中的IO处理和使用,API详细介绍(二)

    字符流 [向文件中写入数据] 现在我们使用字符流 /** * 字符流 * 写入数据 * */ import java.io.*; class hello{ public static void mai ...