对象的深拷贝于浅拷贝

对于基本类型,浅拷贝过程就是对值的复制,这个过程会开辟出一个新的内存空间,将值复制到新的内存空间。而对于引用类型来书,浅拷贝过程就是对指针的复制,这个过程并没有开辟新的堆内存空间,只是将指向该内存的地址进行了复制。然而对引用类型的浅拷贝会出现一个问题,那就是修改其中一个对象的属性,则另一个对象的属性也会改变。产生了问题那必然有相对解决的方法, 就这样深拷贝就开始入场了,深拷贝会开辟新的栈,两个对象对应两个不同的地址,这样一来,改一个对象的属性,也不会改变另一个对象的属性。

下面我们用代码看一下深拷贝于浅拷贝是如何实现的 :

对象的浅拷贝

对象的浅拷贝实现方法很简单,说白了就是一个for in 循环的事情 :

let obj = {
nNum : 1,
sName : 'aaron'
}; function shallowCopy(args) { let result = {}; for(let item in args) {
if(args.hasOwnProperty(item)) {
result[item] = args[item];
};
}; return result;
}; shallowCopy(obj);

或者,我们可以使用最常见的jQuery来实现这个功能 :

$.extend({} , obj);

亦或者,我们也可以采用ES6的方法用一行代码实现相同的功能 :

Object.assign({} , obj);

对于浅拷贝就说到这了,如果有补充或者发现问题的大牛可以回复我或者邮件通知,我会第一时间进行回复,好了废话说多了,我们接下来看一下深拷贝

对象的深拷贝

如果我们把上面的obj稍微修改一下那浅拷贝就有心无力了 :

let obj = {
nNum : 1,
oAar : [1,2,3,4]
};

我们不妨可以再用上面的方法试一下

let newObj = shallowCopy(obj);

newObj === obj      // false
newObj.oAar === obj.oAar // true

从上面的结果显示我们可以看出,newObj.oAar与obj.oAar指针所指的是同一个位置,那我们如何改正这个问题呢?

其实也很容易,我们将obj.oAar再看待为一个新的对象,对其再进行一次浅拷贝不就可以了吗??不说了,上代码

function deepCopy(args) {

    let result = {};

    for(let item in args){
if(typeof args[item] === 'object' && args[item] !== null){
result[item] = deepCopy(args[item]);
}else{
result[item] = args[item];
};
}; return result;
}; result(obj);

我们来验证一下

let newObj = result(obj);

newObj === obj      // false
newObj.oAar === obj.oAar // false

结果也显示我们实现了,ok

但是有没有其他的方式呢,比如说更简洁一些的,也是有的:

我们可以使用jQuery的$.extend(true, {}, obj),同样也可以实现,是不是觉得眼熟。前面我们说浅拷贝的时候也说过这个方法,但是多了一个为true的参数,$.extend()方法,第一个参数默认为false,当设置它为true时则会开启深拷贝模式。

想想还有没有什么其他的方式= ̄ω ̄=?

其实还有一个捷径可走

还是上面举的那个obj,我们对它再进行一次尝试

 let obj = {
nNum : 1,
oAar : [1,2,3,4]
}; function deepCopy(args) {
let result = {}; try {
result = JSON.parse(JSON.stringify(args));
} return result;
} let newObj = deepCopy(obj); newObj === obj // false
newObj.oAar === obj.oAar // false

ヾ(。`Д´。) 什么鬼,这样也行? 那还前面说那么多废话,直接上这个方法岂不是爽歪歪?

但是这里不得不说明一点,投机取巧往往能达到看似相同的结果,但是还是存在一些隐性的问题的

就如上面这种方式和递归的方法相比是有弊端的,比如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。

这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。

最后再说一种方法,可以使用Object.create()方法达到深拷贝的效果

function deepCopy(args) {
let result = {}; for(let item in args){
if(typeof args[item] === 'object' && args[item] !== null){
result[item] = args[item].constructor === Array ? [] :
Object.create(prop);
}else{
result[item] = args[item];
};
}; return result;
} let newObj = deepCopy(obj); newObj === obj // false
newObj.oAar === obj.oAar // false

好了,更多的第三方库的方法我们就不一一列举了,原理更重要嘛,对吧。

最后我们来总结一下:

浅拷贝我们说了3种方法 :

  • 通过for...in循环来实现
  • 通过Object.assign()方法来实现
  • 通过jQuery中的$.extend()方法来实现

深拷贝我们同样说了四种方法 :

  • 通过递归的手法实现
  • 通过jQuery中的$.extend()添加true参数方法来实现
  • 通过JSON序列化反序列化来实现
  • 用过Object.create()方法来实现

除了这几种如果各位还想到了其他什么好的方法欢迎下方留言ヾ( ̄▽ ̄)

js中的深拷贝与浅拷贝的更多相关文章

  1. js 中的深拷贝与浅拷贝

    在面试中经常会问到js的深拷贝和浅拷贝,也常常让我们手写,下面我们彻底搞懂js的深拷贝与浅拷贝. 在js中 Array 和 Object  这种引用类型的值,当把一个变量赋值给另一个变量时,这个值得副 ...

  2. js 中的 深拷贝与浅拷贝

    js在平时的项目中,赋值操作是最多的:比如说: var person1 = { name:"张三", age:18, sex:"male", height:18 ...

  3. js中的深拷贝和浅拷贝2

    所谓 深浅拷贝: 对于仅仅是复制了引用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响,为 浅拷贝. 而如果是在堆中重新分配内存,拥有不同的地址,但是值是一 ...

  4. JS中的深拷贝和浅拷贝

    浅拷贝 浅拷贝是拷贝第一层的拷贝 使用Object.assign解决这个问题. let a = { age: 1 } let b = Object.assign({}, a) a.age = 2 co ...

  5. JS对象复制(深拷贝、浅拷贝)

    如何在 JS 中复制对象 在本文中,我们将从浅拷贝(shallow copy)和深拷贝(deep copy)两个方面,介绍多种 JS 中复制对象的方法. 在开始之前,有一些基础知识值得一提:Javas ...

  6. javascript中的深拷贝与浅拷贝

    javascript中的深拷贝与浅拷贝 基础概念 在了解深拷贝与浅拷贝的时候需要先了解一些基础知识 核心知识点之 堆与栈 栈(stack)为自动分配的内存空间,它由系统自动释放: 堆(heap)则是动 ...

  7. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

  8. C语言中的深拷贝和浅拷贝

    //C语言中的深拷贝和浅拷贝 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #inc ...

  9. 浅谈Java中的深拷贝和浅拷贝

    转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...

随机推荐

  1. IdentityServer Topics(3)- 定义客户端

    客户端代表可以从您的身份服务器请求令牌的应用程序. 细节有所不同,但您通常为客户端定义以下常用设置: 一个唯一的客户端ID 一个密钥,如果需要 允许与令牌服务的交互(称为授权类型) 身份或访问令牌被发 ...

  2. deeplearning.ai 改善深层神经网络 week2 优化算法 听课笔记

    这一周的主题是优化算法. 1.  Mini-batch: 上一门课讨论的向量化的目的是去掉for循环加速优化计算,X = [x(1) x(2) x(3) ... x(m)],X的每一个列向量x(i)是 ...

  3. BZOJ:4530: [Bjoi2014]大融合

    4530: [Bjoi2014]大融合 拿这题作为lct子树查询的练手.本来以为这会是一个大知识点,结果好像只是一个小技巧? 多维护一个虚边连接着的子树大小即可. #include<cstdio ...

  4. HDU 1005 Number Sequence【多解,暴力打表,鸽巢原理】

    Number Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  5. UVA - 10339-Watching Watches

    10339 - Watching Watches Time limit: 3.000 seconds It has been said that a watch that is stopped kee ...

  6. POJ_2769同余问题

    Reduced ID Numbers Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9310   Accepted: 374 ...

  7. eclipse中git提交冲突问题

    1.工程->Team->同步:  2.从远程pull至本地,就会出现如下内容:  3.使用Merge Tool,执行第二项 使用HEAD合并后的效果: 4.再手动修改 4.修改后的文件需要 ...

  8. DB 注意事项 优化数据库查询

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...

  9. 如何初始化grunt

    为什么使用任务运行工具Grunt -- 官方解释 简而言之,自动化.当你处理诸如代码最小化, 代码编译, 单元测试, 代码规范校验等等重复任务时, 你必须要做的工作越少,你的工作就变得越简单.在你完成 ...

  10. 一个域名最多能对应几个IP地址?,一个IP地址可以绑定几个域名?

    一个域名最多能对应几个IP地址?,一个IP地址可以绑定几个域名?谢谢 xikeboy | 浏览 31055 次 推荐于2016-04-24 14:21:14 最佳答案 1.也就是说通常情况下一个域名同 ...