Javascript/js 的浅拷贝与深拷贝(复制)学习随笔
js变量的数据类型值分基本类型值和引用类型值。
在ES6(ECMAScript6)以前,基本数据类型包括String、Number、Boolean、Undefined、Null。
基本类型值的复制(拷贝)
从一个变量向另一个变量复制基本类型的值。使用赋值操作符 ' = ' 即可。
如:
var num1 = 1, num2;
num2 = num1;

上述代码定义了两个变量num1、num2。num1初始化值是1,num2是undefined。接着把num1赋值给num2。
num1的值与num2的值增删改减完全独立、互不影响。
++num1;
num2 = null;
// 2 null
拓展:基于基本类型值,ES提供了三个特殊的引用类型。String、Number、Boolean。(基本包装类型)
var num3 = 3;
var num4 = num3.toFixed(2);
console.log(num3, num4); // 3 3.00
如上,变量num3包含一个数字值,数字当然属于基本类型值啦,接着num3调用了toFixed()方法。并将返回结果保存在num4中。最后在控制台输出下。结果是3 3.00。当然了,没有报错。。
一般来理解,基本类型值不是对象,不应该有方法。(但是它们确实有方法.。查看它们有哪些方法的一个办法是在chrome控制台console.log(new Number(1))。其他基本类型值同理。baidu/翻书/强记。do whatever you want)
当第二行代码访问num3时,访问过程处于一种读取模式,也就是从内存中读取这个变量的值。此时,在后台,大概是执行了下列的es代码:
var _num3 = new Number(3);// 创建Number类型的一个实例
var _num4 = _num3.toFixed(2);// 在实例上调用指定的方法
_num3 = null;// 销毁这个实例
return _num4;// 可以想象成在一个函数里执行这里的4行代码,函数返回_num4。接着被num4接收。
这也意味着我们可以对基本类型值做一些扩展。比如:
var num5 = 1;
Number.prototype.addTen = function () {
var res = this + 10;
return res;
};
console.log(num5.addTen());// 11
如上,在Number原型上定义addTen()方法,所有Number类型值都可以调用这个方法。
其他基本类型值同理。
ES6规范引入了一项新特性--symbol,它也是一种基本数据类型,它的功能类似于一种标识唯一性的ID。
调用Symbol函数来创建一个Symbol实例:
const S1 = Symbol();
// 可以在调用Symbol函数时传入一个参数,相当于给你创建的Symbol实例一个描述信息。参数可选,可以是任意可转化成字符串的值。
const S2 = Symbol('id9527');
引用类型的复制(拷贝)
常见的引用类型包括 Object、Aarry、Date、Function、RegExp...
引用类型值是引用类型的一个实例。
通过赋值操作符‘=’复制的引用类型值。实际上复制的是一个指针(地址)。该指针指向存储在堆中的对象。
const obj1 = new Object();
const obj2 = obj1;
obj1.name = 'xm';
console.log(obj2.name);// xm
obj1与obj2指向同一个对象,对obj1的修改,同样作用于obj2。

多数时候这不是我们想要的结果。我们需要的是两个相互独立而又长得一模一样的对象。
由于引用类型值也可能包含引用类型值。由此就派生出了浅拷贝和深拷贝。
浅拷贝
数组的浅拷贝常用方法:
(1)concat方法
const arr1 = ['a', 'b', ['c', 4]];
const arr2 = arr1.concat([]);
console.log(arr2, arr1 == arr2);// ['a', 'b', ['c', 4]] false
(2)slice方法
const arr1 = ['a', 'b', ['c', 4]];
const arr2 = arr1.slice(0);
console.log(arr2, arr1 == arr2);// ['a', 'b', ['c', 4]] false
(3)扩展运算符...方法
const arr1 = ['a', 'b', ['c', 4]];
const arr2 = [...arr1];
// const [...arr2] = arr1; // 等同于上一行
console.log(arr2, arr1 == arr2);// ['a', 'b', ['c', 4]] false
(4)map方法
const arr1 = ['a', 'b', ['c', 4]];
const arr2 = arr1.map(item => item);
console.log(arr2, arr1 == arr2);// ['a', 'b', ['c', 4]] false
(5)filter方法 把上面的map改成filter即可。
...for循环、forEach、for of、splice、Object.values等方法均可。
对象的浅拷贝常用方法:
1、for in遍历方法
const obj = {
say(){
console.log('hello');
}
};
const obj1 = Object.create(obj);
obj1.a = '对象';
obj1.b = [1, 2, 3];
// const obj2 = Object.create(obj); // 继承obj的属性、方法
const obj2 = {};
for (let p in obj1) {
if (obj1.hasOwnProperty(p)) {
obj2[p] = obj1[p];
}
}
如上,obj1的原型对象是obj,浅拷贝一般不需要拷贝原型上的属性和方法,而for in循环可以枚举原型上的属性和方法。使用hasOwnProperty()方法过滤掉原型的属性和方法。
结果如下:

(2)Object.entries()方法
const obj = {
say(){
console.log('hello');
}
};
const obj1 = Object.create(obj);
obj1.a = '对象';
obj1.b = [1, 2, 3];
// const obj2 = Object.create(obj); // 继承obj的属性、方法
const obj2 = {};
Object.entries(obj1).forEach(([key, value]) => obj2[key] = value);

之所以称为浅拷贝,其原因在于如果引用类型值里包含引用类型值,上述的所有方法,在对里层的引用类型值复制操作时,使用的还是赋值操作符'='。如下所示:

如果修改了obj1.b的值,同样会作用于obj2。

深拷贝
以下是实现对数组、对象深拷贝的一种方法。
采用递归的方式,层层遍历。
const deepClone = function handleDeepClone(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let _obj;
if (obj instanceof Array) {
_obj = [];
obj.forEach((item, i) => _obj[i] = handleDeepClone(item));
} else {
_obj = {};
Object.entries(obj).map(([key, value]) => _obj[key] = handleDeepClone(value));
}
return _obj;
};
结果如下:

Javascript/js 的浅拷贝与深拷贝(复制)学习随笔的更多相关文章
- js对象浅拷贝和深拷贝详解
js对象浅拷贝和深拷贝详解 作者:i10630226 字体:[增加 减小] 类型:转载 时间:2016-09-05我要评论 这篇文章主要为大家详细介绍了JavaScript对象的浅拷贝和深拷贝代码,具 ...
- [转] js对象浅拷贝和深拷贝详解
本文为大家分享了JavaScript对象的浅拷贝和深拷贝代码,供大家参考,具体内容如下 1.浅拷贝 拷贝就是把父对像的属性,全部拷贝给子对象. 下面这个函数,就是在做拷贝: var Chinese = ...
- javascript中的浅拷贝和深拷贝 分类: JavaScript 2015-05-07 15:29 831人阅读 评论(1) 收藏
1.js对象浅拷贝 简单的赋值就是浅拷贝.因为对象和数组在赋值的时候都是引用传递.赋值的时候只是传递一个指针. 看下面的实例代码: var a = [1,2,3]; var b =a ; var te ...
- javascript中的浅拷贝和深拷贝(拷贝引用和拷贝实例)
作者:千锋教育链接:https://www.zhihu.com/question/23031215/answer/326129003来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
- js实现浅拷贝和深拷贝
实现浅拷贝和深拷贝 1. 浅拷贝和深拷贝的区别 简单点说,浅拷贝拷贝完后,修改拷贝的内容可能会对源内容产生影响.而深拷贝就是拷贝前后的内容相互不影响. 那为什么拷贝前后的内容会相互影响呢? ...
- Javascript中的浅拷贝和深拷贝
很多开发语言中都有浅拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现. 在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用 ...
- js中浅拷贝和深拷贝以及深拷贝的实现
前言:2019年的第一篇分享... 一.什么是基本类型值和引用类型值?ECMAScript包括两个不同类型的值:基本数据类型和引用数据类型.基本数据类型指的是简单的数据段,引用数据类型指的是有多个值构 ...
- js的浅拷贝和深拷贝和应用场景
为什么会用到浅拷贝和深拷贝 首先来看一下如下代码 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e ...
- 小tips:JS之浅拷贝与深拷贝
浅拷贝: function extendCopy(p) { var c = {}; for (var i in p) { c[i] = p[i]; } return c; } 深拷贝: functio ...
随机推荐
- 重新学习Spring注解——声明式事务
36.声明式事务-环境搭建 37.声明式事务-测试成功 38.[源码]-声明式事务-源码分析 /** * 声明式事务: * * 环境搭建: * 1.导入相关依赖 * 数据源.数据库驱动.Spring- ...
- USACO Party Invitations
洛谷 P3068 [USACO13JAN]派对邀请函Party Invitations 洛谷传送门 JDOJ 2343: USACO 2013 Jan Silver 3.Party Invitatio ...
- React和Redux的开发经验之谈
1.显示控制用state,共享数据用redux,觉得可以不用redux的就不要用 2.表单项集中的地方,推荐用高阶组件,单个表单项,不推荐用高阶组件 3.涉及对服务数据的处理,在redux的model ...
- 【jupyter】文件解压
Jupyter使用便捷,但是不能上传文件夹.可以将文件夹压缩,上传后再利用python或者terminal进行解压. windows 可以用python的zipfile包来解压.比如: import ...
- VMware Workstation创建Windows2012server虚拟机
镜像文件需要下载到物理机 3.需要输入iso文件 对应的密钥 定义普通的用户名与密码 4.指定按照路径 5. 大概都是下一步 根据提示需要重启 选择带GUI的服务器进行安装,因为windows命令行模 ...
- 一本通 1615:【例 1】序列的第 k 个数
传送门 我在这里! 思路 输入一个序列的前三个数并求出这个序列的第K项,这个数列不是等比序列就是等差数列,等差数列比较好判断,如果序列中\(a_{i+2}-a_{i+1}=a_{i+1}-a_{i}\ ...
- Venn 维恩图的绘制
使用在线绘图工具 https://bioinfogp.cnb.csic.es/tools/venny/index.html http://www.biovenn.nl/index.php http:/ ...
- concurrent(三)互斥锁ReentrantLock & 源码分析
参考文档:Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock:http://www.cnblogs.com/skywang12345/p/3496101.html Reentr ...
- cad快捷图标中的启动参数
!!!转载 http://blog.sina.com.cn//s/blog_6848608101017v4w.html 有时候需要判断一下是否是硬件加速.Ribbon等原因造成了软件的问题,需要在 ...
- Python 的 Pandas 对矩阵的行进行求和
Python 的 Pandas 对矩阵的行进行求和: 若使用 df.apply(sum) 方法的话,只能对矩阵的列进行求和,要对矩阵的行求和,可以先将矩阵转置,然后应用 df.apply(sum) 即 ...