javascript篇-浅拷贝与深拷贝
理解javascript 的浅拷贝与深拷贝,首先看一下js的数据类型:
js有5种基本数据类型:undefined,null,boolean,number,string
还有一种复杂的数据类型(也叫引用类型),即 对象
1.对于基本数据类型:
他们的值在内存中占据着固定大小的空间,并被保存在栈内存中。当一个变量向另一个变量复制基本类型的值,会创建这个值的副本,并且我们不能给基本数据类型的值添加属性

上面代码中:a是基本数据类型(number),b是a的一个副本,它们两者都占有不同的内存空间,其中一个值的改变不会影响另一个值。
2.对于引用类型:
复杂的数据类型即是引用类型,它的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针地址而已,因此两个变量最终都指向同一个对象

上述代码中,将a的值赋值给b以后,b的值得改变也导致了a的值的改变,这其实就是浅拷贝
但是很多情况下这都不是我们要的效果,我们希望b的改变不会影响到a,这就是下面要将的深拷贝了,
(1) 数组的深拷贝
对于数组我们可以使用slice()和concat()方法来实现深拷贝,

(2) 对象的深拷贝
1:手动复制:

这种比较麻烦,而切属性多层嵌套的情况下,也必须要手动嵌套复制,否则,还是会改变
像这种对象只有一层的情况下可以使用Object.assign()函数(函数参考:https://blog.csdn.net/qs8lk88/article/details/79018481)

3. 转成Json再转回来

这样做是真正的Deep Copy,这种方法简单易用。
但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。
这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。
也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON。
4. 递归拷贝
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
if (typeof initalObj[i] === 'object') {
obj[i] = (initalObj[i].constructor === Array) ? [] : {};
arguments.callee(initalObj[i], obj[i]);
} else {
obj[i] = initalObj[i];
}
}
return obj;
}
var str = {};
var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);
上述代码确实可以实现深拷贝。但是当遇到两个互相引用的对象,会出现死循环的情况。
为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。
改进版代码如下:
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else {
obj[i] = prop;
}
}
return obj;
}
var str = {};
var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);
5、使用Object.create()方法
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
} else {
obj[i] = prop;
}
}
return obj;
}
直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。
6. jquery 有提供一个$.extend可以用来做 Deep Copy。
7. 另外一个很热门的函数库lodash,也有提供_.cloneDeep用来做 Deep Copy。
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false
javascript篇-浅拷贝与深拷贝的更多相关文章
- 全面聊聊JavaScript的浅拷贝和深拷贝
一.背景 首先我们可以看下面这段简单的代码: var obj = {name:'程序猿',sex:'男'}; var arr = ['程序猿','程序媛']; var copyobj = o ...
- 关于JavaScript的浅拷贝和深拷贝
在 JS 中有一些基本类型像是Number.String.Boolean,而对象就是像这样的东西{ name: 'Larry', skill: 'Node.js' },对象跟基本类型最大的不同就在于他 ...
- JavaScript中浅拷贝和深拷贝的区别和实现
深拷贝和浅拷贝的区别 浅拷贝(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存: 深拷贝(deep copy):复制并创建一个一摸一样的对象,不共 ...
- python 进阶篇 浅拷贝与深拷贝
阐述引用.浅拷贝和深拷贝前,首先需要要了解 Python 的世界里,一切皆对象,每个对象各包含一个 idendity.type 和 value. 引用(Reference) >>> ...
- JavaScript中浅拷贝和深拷贝的区别
JavaScript数据类型 基础数据类型:保存在栈内存中的简单数据段 ,有undefined,boolean,number,string,null 引用数据类型:Array,object,Funct ...
- javascript的浅拷贝和深拷贝
1.浅拷贝:复制一份引用,所有引用对象都指向一份数据,并且都可以修改这份数据. 2.深拷贝(复杂):复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制. 这里画一个简单的图来加深理解: ...
- JavaScript 数据结构与算法之美 - 栈内存与堆内存 、浅拷贝与深拷贝
前言 想写好前端,先练好内功. 栈内存与堆内存 .浅拷贝与深拷贝,可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScri ...
- Javascript中的浅拷贝和深拷贝
很多开发语言中都有浅拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现. 在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用 ...
- javascript中的浅拷贝和深拷贝(拷贝引用和拷贝实例)
作者:千锋教育链接:https://www.zhihu.com/question/23031215/answer/326129003来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
随机推荐
- iOS开发之--解决 swap file “*.swp”already exists!问题
刚才我在vim导入第三方库的时候,突然发现我把podfile的名字打错了,然后我直接终止了进程,然后你懂得出错了,,E325......., 其实使用vim编辑文件实际上是先copy一份临时文件,病映 ...
- ios开发之--给WebView加载进度条
不是新东西,就是在项目里面用到H5页面的时候,中间加载延迟的时候,在最上面加载一个进度条,代码如下: // 获取屏幕 宽度.高度 bounds就是屏幕的全部区域 #define KDeviceWidt ...
- 关于pyinstall打包时的依赖问题
前几天写了一个人脸表情分析的小程序,想用pyinstall打包成一个可以移植的小软件.因为之前用过pyinstall,所以这次使用同样的方法对我的程序进行打包: [pyinstaller -F --i ...
- Sciter返回json
sciter::value arr[200]; for (int i = 0; i < (int)m_fileList.size(); i++) { cv::Mat img = cv::imre ...
- Python变量访问权限控制
oop1.py文件代码 # user/bin/python class Foo: def bar(self): print('ok') def hello(self, name): print(&qu ...
- 时间模块和random模块
时间模块 和时间有关系的我们就要用到时间模块.在使用模块之前,应该首先导入这个模块. #常用方法 1.time.sleep(secs) (线程)推迟指定的时间运行.单位为秒. 2.time.time( ...
- vue使用render渲染&jsx
vue&jsx文档 vue实例属性 // App.ts import hBtn from './components/hBtn' import hUl from './components/h ...
- 拓展 NLog 优雅的输送日志到 Logstash
在上上篇博客通过对aspnetcore启动前配置做了一些更改,以及对nlog进行了自定义字段,可以把请求记录输送到mysql,正式情况可能不会这么部署.因为近期也在学习elk,所以就打算做一个实例,结 ...
- 二进制安装mysql
1.1 MySQL安装介绍 mysql软件下载地址信息: www.mysql.com mirrors.sohu.com mysql软件下载完毕后,查看mysql解压后目录文件大小 1.下载解压my ...
- 关于device tree中的interrupts选项
http://blog.csdn.net/jiang__jiang/article/details/52064715 随着Linux的发展,dts技术是大势所趋.里面的interrupts = < ...