前端工程师应该都比较熟悉浅拷贝和深拷贝的概念,在日常业务代码的过程中,特别是做数据处理的时候,经常行的会遇到,比如如何在不修改原对象的基础上,重新生成一个一模一样的对象,加以利用,又或是,如何巧妙地运用相关的内置API,来达成自己所需要的结果,比如数组相关的操作,splice和slice就是截然相反的处理,虽然同样是对数组进行截取操作,但是前者会影响原数组,后者则是返回一个新的数组对象,而对原来的数组并不会产生任何影响,这其中的差别,需要有一定的开发经验才能明白。

  好了,废话也不多说,下面来简单谈谈深拷贝与浅拷贝之间的那些事儿:

  一、什么是浅拷贝,什么是深拷贝

  从名字上,就能看出来,这哥俩确实是有很大的区别,是对于复制方式的差别。浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存(内存区域没有隔离)。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存(内存区域隔离),修改新对象不会改到原对象。在多层对象上,浅拷贝只拷贝一层,而深拷贝则会层层迭代,直到最后一层里只有 基本类型值,没有复杂类型的值,比如对象或者是数组。

浅拷贝举例

var Chinese = {
  nation:'中国'
};
var Doctor ={
  career:'医生'
}
function extendCopy(p) {
  var c = {};
  for (var i in p) {
    c[i] = p[i];
  }
  return c;
}
var Doctor = extendCopy(Chinese);
Doctor.career = '医生';
alert(Doctor.nation); // 中国

深拷贝举例

function deepCopy(p, c) {
  var c = c || {};
  for (var i in p) {
    if (typeof p[i] === 'object') {
      c[i] = (p[i].constructor === Array) ? [] : {};
      deepCopy(p[i], c[i]);
    } else {
      c[i] = p[i];
    }
  }
  return c;
}

二、深拷贝的实现方式

1、ES6为我们提供了一种十分好用的方法,Object.assign(target, ...source)方法,assign方法接受多个参数,第一个参数target为拷贝目标,剩余参数...source是拷贝源。此方法可以将...source中的属性复制到target中,同名属性会进行覆盖,并且在复制过程中实现了'伪'深拷贝

let foo = {
a: 1,
b: 2,
c: {
d: 1,
}
}
let bar = {};
Object.assign(bar, foo);
foo.a++;
foo.a === 2 //true
bar.a === 1 //true

乍一看,好像已经实现了深拷贝的效果,对foo.a进行的操作并没有体现在bar.a中,但是再往后看

foo.c.d++;
foo.c.d === 2 //true
bar.c.d === 1 //false
bar.c.d === 2 //true

Object.assign()的拷贝类型十分明显了,这是一种可以对非嵌套对象进行深拷贝的方法,如果对象中出现嵌套情况,那么其对被嵌套对象的行为就成了普通的浅拷贝.

如果真的想进行深拷贝,最简单粗暴地方式就是JSON操作.

JSON对象中包含两个方法, stringify()和parse(),前者可以将对象JSON化,而后者可以将JSON格式转换为对象.这是一种可以实现深拷贝的方法.

但这种方法的缺陷是会破坏原型链,并且无法拷贝属性值为function的属性

所以如果只是想单纯复制一个嵌套对象,可以使用此方法

let foo = {
a: 1,
b: {
c: 1
}
}
let bar = JSON.parse(JSON.stringify(foo));

2、jQuery提供了一个可以用来做深拷贝的方法,就是$.extend

var $ = require('jquery');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f);
// false

另外lodash也有提供_.cloneDeep来做深拷贝操作。

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

3、递归实现深拷贝

function clone( o ) {
var temp = {};
for( var k in o ) {
if( typeof o[ k ] == 'object' ){
temp[ k ] = clone( o[ k ] );
} else {
temp[ k ] = o[ k ];
}
}
return temp;
}

这是本人在开发过程中实际总结的相关方法,也是比较有效的方法,如果大家有更好的方法,也欢迎留言。

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

  1. 浅谈js中的浅拷贝和深拷贝

    在js中如何把一个对象里的属性和方法复制给另一个对象呢? 下面举一个例子来说明: var person={name:'chen',age:18}; var son={sex:'男'}; functio ...

  2. 浅谈JS中的闭包

    浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...

  3. 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂

    浅谈JS中的!=.== .!==.===的用法和区别   var num = 1;     var str = '1';     var test = 1;     test == num  //tr ...

  4. 浅谈JS中 var let const 变量声明

    浅谈JS中 var let const 变量声明 用var来声明变量会出现的问题: 1. 允许重复的变量声明:导致数据被覆盖 2. 变量提升:怪异的数据访问.闭包问题 3. 全局变量挂载到全局对象:全 ...

  5. 由项目浅谈JS中MVVM模式

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.    背景 最近项目原因使用了durandal.js和knock ...

  6. js架构设计模式——由项目浅谈JS中MVVM模式

    1.    背景 最近项目原因使用了durandal.js和knockout.js,颇有受益.决定写一个比较浅显的总结. 之前一直在用SpringMVC框架写后台,前台是用JSP+JS+标签库,算是很 ...

  7. js中的浅拷贝和深拷贝

    说说最近所学:浅拷贝和深拷贝也叫做浅克隆和深克隆,深浅主要针对的是对象的"深度",常见的对象都是"浅"的,也就是对象里的属性就是单个的属性,而"深&q ...

  8. JS中的浅拷贝与深拷贝

    浅拷贝与深拷贝的区别: 浅拷贝: 对基本类型和引用类型只进行值的拷贝,即,拷贝引用对象的时候,只对引用对象的内存地址拷贝,新旧引用属性指向同一个对象,修改任意一个都会影响所有引用当前对象的变量. 深拷 ...

  9. 浅谈js中的数据类型,使用typeof获取js数据类型

    JS中的数据类型 1):Undefined——值未定义 注:Undefined类型只有一个值,即特色的undefined.在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined ...

随机推荐

  1. CSS3 @keyframes 用法(简单动画实现)

    定义: 通过 @keyframes 规则,能够创建动画. 创建动画的原理是,将一套 CSS 样式逐渐变化为另一套样式. 在动画过程中,可以多次改变这套 CSS 样式. 以百分比来规定改变发生的时间,或 ...

  2. 处理springMvc中responsebody返回中文乱码

    法一:   @RequestMapping(value="/getUsersByPage",produces = public String getUsers  法二:在sprin ...

  3. CSS中可以继承和不可继承的常见属性

    一.无继承性的属性 1.display:规定元素应该生成的框的类型 2.文本属性: vertical-align:垂直文本对齐 text-decoration:规定添加到文本的装饰 text-shad ...

  4. mysql window版本下载

    最小的版本:https://cdn.mysql.com//Downloads/MySQL-5.5/mysql-5.5.54-win32.msi

  5. CentOS常用命令搜集

    centos是32或者64位:getconf LONG_BIT

  6. 使用Websocket框架之GatewayWorker开发电商平台买家与卖家实时通讯

    前段时间公司提了一个新的需求,在商品的详情页要实现站内买家和商品卖家实时通讯的功能以方便沟通促成交易,要开发此功能当时首先考虑到的就是swoole和workerman了,从网上大概了解了一下关于这两款 ...

  7. 2018年最完整5大网页设计图标解决方案:Font Awesome奥森图Unicode、CSS 和、Font以及国产zfont图标集

    网上有很多高质量的图标,基于icon的关键词能在Google上搜索到不少内容,不考虑版权外还要修改大小.颜色等等,现在介绍一些替代方案:Unicode.CSS 和 Font,它具有更高的灵活性. 方案 ...

  8. Java集合框架(六)—— Collections工具类

    操作集合的工具类Collections Java提供了一个操作Set.List和Map等集合的工具类:Collections,该工具类里提供了大量方法对集合元素进行排序.查询和修改等操作,还提供了将集 ...

  9. es6之let和const命令的一些笔记

    let和const命令 let命令 基本用法 let命令用来声明变量,声明的变量只在命令所在的代码块内有效.for循环中很适合使用let命令. 有必要理解的例子: var a = []; for (v ...

  10. 试着简单易懂记录synchronized this object Class的区别,模拟ConcurrentHashMap

    修饰静态方法默认获取当前class的锁,同步方法没有释放的锁,不影响class其他非同步方法的调用,也不影响不同锁的同步方法,更不影响使用class的其他属性. package thread.base ...