js 对象 浅拷贝 和 深拷贝

1.浅拷贝

拷贝就是把父对像的属性,全部拷贝给子对象。

下面这个函数,就是在做拷贝:

  1. var Chinese = {
  2.   nation:'中国'
  3. }
  4. var Doctor = {
  5.   career:'医生'
  6. }  
  7. function extendCopy(p) {
  8.     var c = {};
  9.     for (var i in p) {
  10.       c[i] = p[i];
  11.     }
  12.     c.uber = p;
  13.     return c;
  14.  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

使用的时候,这样写:

  1. var Doctor = extendCopy(Chinese);
  2. Doctor.career = '医生';
  3. alert(Doctor.nation); // 中国
  • 1
  • 2
  • 3

但是,这样的拷贝有一个问题。那就是,如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。

请看,现在给Chinese添加一个”出生地”属性,它的值是一个数组。

  1. Chinese.birthPlaces = ['北京','上海','香港'];
  • 1

通过extendCopy()函数,Doctor继承了Chinese。

  1. var Doctor = extendCopy(Chinese);
  • 1

然后,我们为Doctor的”出生地”添加一个城市:

  1. Doctor.birthPlaces.push('厦门');
  • 1

看一下输入结果

  1. alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
  2. alert(Chinese.birthPlaces); //北京, 上海, 香港, 厦门
  • 1
  • 2

结果是两个的出生地都被改了。

所以,extendCopy() 只是拷贝了基本类型的数据,我们把这种拷贝叫做“浅拷贝”。

2.深拷贝

因为浅深拷有如此弊端所以我们接下来看一下深拷贝

所谓”深拷贝”,就是能够实现真正意义上的数组和对象的拷贝。它的实现并不难,只要递归调用”浅拷贝”就行了。

  1. function deepCopy(p, c) {
  2.     var c = c || {};
  3.     for (var i in p) {
  4.       if (typeof p[i] === 'object') {
  5.         c[i] = (p[i].constructor === Array) ? [] : {};
  6.         deepCopy(p[i], c[i]);
  7.       } else {
  8.          c[i] = p[i];
  9.       }
  10.     }
  11.     return c;
  12.   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

看一下使用方法:

  1. var Doctor = deepCopy(Chinese);
  • 1

现在,给父对象加一个属性,值为数组。然后,在子对象上修改这个属性:

  1. Chinese.birthPlaces = ['北京','上海','香港'];
  2. Doctor.birthPlaces.push('厦门');
  3. alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
  4. alert(Chinese.birthPlaces); //北京, 上海, 香港
  • 1
  • 2
  • 3
  • 4
  • 5

这样就完成了拷贝;

$.extend()

jquery 中$.extend()如同。

$.extend( [deep ], target, object1 [, objectN ] )

  • deep
    类型: Boolean
    如果是true,合并成为递归(又叫做深拷贝)。
  • target
    类型: Object
    对象扩展。这将接收新的属性。
  • object1
    类型: Object
    一个对象,它包含额外的属性合并到第一个参数.
  • objectN
    类型: Object
    包含额外的属性合并到第一个参数

当我们提供两个或多个对象给$.extend(),对象的所有属性都添加到目标对象(target参数)。

如果只有一个参数提供给$.extend(),这意味着目标参数被省略。在这种情况下,jQuery对象本身被默认为目标对象。这样,我们可以在jQuery的命名空间下添加新的功能。这对于插件开发者希望向 jQuery 中添加新函数时是很有用的。

请记住,目标对象(第一个参数)将被修改,并且将通过$.extend()返回。然而,如果我们想保留原对象,我们可以通过传递一个空对象作为目标对象:

  1. var object = $.extend({}, object1, object2);
  • 1

在默认情况下,通过$.extend()合并操作不是递归的;如果第一个对象的属性本身是一个对象或数组,那么它将完全 用第二个对象相同的key重写一个属性。这些值不会被合并。可以通过检查下面例子中 banana 的值,就可以了解这一点。然而,如果将 true 作为该函数的第一个参数,那么会在对象上进行递归的合并。

警告:不支持第一个参数传递 false 。

1. 合并两个对象,并修改第一个对象。

  1. var object1 = {
  2. apple: 0,
  3. banana: { weight: 52, price: 100 },
  4. cherry: 97
  5. };
  6. var object2 = {
  7. banana: { price: 200 },
  8. durian: 100
  9. };
  10. // Merge object2 into object1
  11. $.extend( object1, object2 );
  12. // Assuming JSON.stringify - not available in IE<8
  13. console.log( JSON.stringify( object1 ) );
  14. //{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2. 采用递归方式合并两个对象,并修改第一个对象。

  1. var object1 = {
  2. apple: 0,
  3. banana: { weight: 52, price: 100 },
  4. cherry: 97
  5. };
  6. var object2 = {
  7. banana: { price: 200 },
  8. durian: 100
  9. };
  10. // Merge object2 into object1, recursively
  11. $.extend( true, object1, object2 );
  12. // Assuming JSON.stringify - not available in IE<8
  13. console.log( JSON.stringify( object1 ) );
  14. //{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3. 合并 defaults 和 options 对象,并且不修改 defaults 对象。这是常用的插件开发模式。

  1. var defaults = { validate: false, limit: 5, name: "foo" };
  2. var options = { validate: true, name: "bar" };
  3. // Merge defaults and options, without modifying defaults
  4. var settings = $.extend( {}, defaults, options );
  5. console.log(JSON.stringify( defaults ));
  6. console.log(JSON.stringify( options ));
  7. console.log(JSON.stringify( settings ));
  8. //defaults -- {"validate":false,"limit":5,"name":"foo"}
  9. //options -- {"validate":true,"name":"bar"}
  10. //settings -- {"validate":true,"limit":5,"name":"bar"}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Javascript 判断对象是否相等

在Javascript中相等运算包括”==”,”===”全等,两者不同之处,不必多数,本篇文章我们将来讲述如何判断两个对象是否相等? 你可能会认为,如果两个对象有相同的属性,以及它们的属性有相同的值,那么这两个对象就相等。那么下面我们通过一个实例来论证下:

  1. var obj1 = {
  2. name: "Benjamin",
  3. sex : "male"
  4. }
  5. var obj2 = {
  6. name: "Benjamin",
  7. sex : "male"
  8. }
  9. //Outputs: false
  10. console.log(obj1 == obj2);
  11. //Outputs: false
  12. console.log(obj1 === obj2);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

通过上面的例子可以看到,无论使用”==”还是”===”,都返回false。主要原因是基本类型string,number通过值来比较,而对象(Date,Array)及普通对象通过指针指向的内存中的地址来做比较。看下面一个例子:

  1. var obj1 = {
  2. name: "Benjamin",
  3. sex : "male"
  4. };
  5. var obj2 = {
  6. name: "Benjamin",
  7. sex : "male"
  8. };
  9. var obj3 = obj1;
  10. //Outputs: true
  11. console.log(obj1 == obj3);
  12. //Outputs: true
  13. console.log(obj1 === obj3);
  14. //Outputs: false
  15. console.log(obj2 == obj3);
  16. //Outputs: false
  17. console.log(obj2 === obj3);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

上例返回true,是因为obj1和ob3的指针指向了内存中的同一个地址。和面向对象的语言(Java/C++)中值传递和引用传递的概念相似。 因为,如果你想判断两个对象是否相等,你必须清晰,你是想判断两个对象的属性是否相同,还是属性对应的值是否相同,还是怎样?

  1. function person(name) {
  2. this.name=name;
  3. }
  4. var p1 = new person("p1");
  5. var p2 = new person("p2");
  6. console.log(p1 == p2); //false
  7. person.prototype.sayHi = function() {
  8. // do sayHi here
  9. }
  10. console.log(p1.sayHi() == p2.sayHi()); //true
  11. console.log(p1.sayHi() === p2.sayHi()); //true
  12.  
  13. 转载 http://blog.csdn.net/i10630226

超实用的JavaScript代码段 Item8 -- js对象的(深)拷贝的更多相关文章

  1. 前端福利!10个短小却超实用的JavaScript 代码段

    JavaScript正变得越来越流行,它已经成为前端开发的第一选择,并且利用基于JavaScript语言的NodeJS,我们也可以开发出高 性能的后端服务,甚至我还看到在硬件编程领域也出现了JavaS ...

  2. 推荐10 个短小却超实用的 JavaScript 代码段

    1. 判断日期是否有效 JavaScript中自带的日期函数还是太过简单,很难满足真实项目中对不同日期格式进行解析和判断的需要.jQuery也有一些第三方库来使日期相关的处理变得简单,但有时你可能只需 ...

  3. 《超实用的JavaScript代码段》—— 读后总结

    这本书全是代码,从头到尾跟着坐下来确实收获很多.比那些古板的教科书式的理解更多,不过书中并不是每个例子都做了,有的作者封装的太多,觉得看了收获不多,就没细看——比如模块渐变.有空好好学学这段的代码. ...

  4. 超实用的JavaScript代码段

    1. 判断日期是否有效 JavaScript中自带的日期函数还是太过简单,很难满足真实项目中对不同日期格式进行解析和判断的需要.JQuery也有一些第三方库来使日期相关的处理变得简单,但有时你可能只需 ...

  5. 超实用的JavaScript代码段 --倒计时效果

    现今团购网.电商网.门户网等,常使用时间记录重要的时刻,如时间显示.倒计时差.限时抢购等,本文分析不同倒计时效果的计算思路及方法,掌握日期对象Date,获取时间的方法,计算时差的方法,实现不同的倒时计 ...

  6. 超实用的JavaScript代码段 Item5 --图片滑动效果实现

    先上图 鼠标滑过那张图,显示完整的哪张图,移除则复位: 简单的CSS加JS操作DOM实现: <!doctype html> <html> <head> <me ...

  7. 超实用的JavaScript代码段 Item1 --倒计时效果

    现今团购网.电商网.门户网等,常使用时间记录重要的时刻,如时间显示.倒计时差.限时抢购等,本文分析不同倒计时效果的计算思路及方法,掌握日期对象Date,获取时间的方法,计算时差的方法,实现不同的倒时计 ...

  8. 超实用的JavaScript代码段 Item4 --发送短信验证码

    发送短信验证码 实现点击“发送验证码”按钮后,按钮依次显示为“59秒后重试”.“58秒后重试”…直至倒计时至0秒时再恢复显示为“发送验证码”.在倒计时期间按钮为禁用状态 . 第一步.获取按钮.绑定事件 ...

  9. 超实用的JavaScript代码段 Item3 --图片轮播效果

    图片轮播效果 图片尺寸 统一设置成:490*170px; 一.页面加载.获取整个容器.所有放数字索引的li及放图片列表的ul.定义放定时器的变量.存放当前索引的变量index 二.添加定时器,每隔2秒 ...

随机推荐

  1. HDU 5826 physics(物理)

     physics(物理) Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)   D ...

  2. HNOI2006-鬼谷子的钱袋

    鬼谷子的钱袋 鬼谷子非常聪明,正因为这样,他非常繁忙,经常有各诸侯车的特派员前来向他咨询时政.有一天,他在咸阳游历的时候,朋友告诉他在咸阳最大的拍卖行(聚宝商行)将要举行一场拍卖会,其中有一件宝物引起 ...

  3. mysql获得自增字段下一个值

    初次研究: 表: sql: show table status from carsale_db LIKE 'tb_car' 结果: 想办法取得这其中的值.... 在Internet上找到这个资料: M ...

  4. Linux基础※※※※如何使用Git in Linux(一)

    参考资料: 1. https://www.linux.com/learn/tutorials/796387-beginning-git-and-github-for-linux-users/ 2. h ...

  5. json、javaBean、xml互转的几种工具介绍 (转载)

    工作中经常要用到Json.JavaBean.Xml之间的相互转换,用到了很多种方式,这里做下总结,以供参考. 现在主流的转换工具有json-lib.jackson.fastjson等,我为大家一一做简 ...

  6. NS3 日志(Logging)、命令行参数、Tracing系统概述(转载)

    NS-3日志子系统的提供了各种查看仿真结果的渠道: 一.使用Logging Module 1 [预备知识]日志级别及其对应的宏 NS-3 提供了若干个日志级别来满足不同的 Debug 需求,每一级的日 ...

  7. R 语言的优劣势是什么?

    R 语言的优劣势是什么? 2015-05-27 程序员 大数据小分析   R,不仅仅是一种语言 本文原载于<程序员>杂志2010年第8期,因篇幅所限,有所删减,这里刊登的是全文. 工欲善其 ...

  8. org.apache.jasper.JasperException: Expecting "jsp:param" standard action with "name" and "value" attributes

      jasper  英 ['dʒæspə]  美 ['dʒæspɚ] 跟读 口语练习 n. 碧玉:墨绿色 n. (Jasper)人名:(德)雅斯佩尔:(西)哈斯佩尔 JasperException 异 ...

  9. Eclipse中配置Tomcat服务器

    在首先外部安装好tomcat,然后在eclipse配置Tomcat服务器: 选择要配置的tomcat版本: 选择tomcat的安装的路径,选择你安装的JRE: 到此tomcat服务器就算是配置好了,接 ...

  10. spring 好处与优点

    使用Spring有什么好处?(1)Spring能有效地组织你的中间层对象.(2)Spring能消除在许多工程中常见的对Singleton的过多使用.(3)Spring能消除各种各样自定义格式的属性文件 ...