A-A+

javascript中的浅拷贝和深拷贝

2016年04月29日 JavaScript 暂无评论 阅读 140 次

1.js对象浅拷贝

简单的赋值就是浅拷贝。因为对象和数组在赋值的时候都是引用传递。赋值的时候只是传递一个指针。

看下面的实例代码:

  1. var a = [1,2,3];
  2. var b =a ;
  3. var test = {name:'xiaohong', age:15};
  4. var c = test;
  5. console.log(a);
  6. console.log(b);
  7. console.log(test);
  8. console.log('-------------------');
  9. b[0] =5;
  10. c.age = 16;
  11. console.log(a);
  12. console.log(b);
  13. console.log(test);
  14. console.log(c);

结果如下:
这里写图片描述

浅拷贝很容易,但是很多时候我们需要原样的把数组或者对象复制一份,在修改值的时候,不改变初始对象的值。这个时候就需要使用深拷贝。

2.js对象深拷贝

因为对象相对较为复杂,所以我们先来看对数组的深拷贝的问题。

数组的深拷贝

  1. //深拷贝
  2. var a = [1,2,3];
  3. var deepArry = [];
  4. /**
  5.  * @param 被复制数组
  6.  * @param 新数组
  7.  */
  8. function deepCopy(arry1, arry2){
  9.     for(var i = 0,l= arry1.length;i<l;i++){
  10.         arry2[i] = arry1[i];
  11.     }
  12. }
  13. deepCopy(a,deepArry);
  14. console.log(a);
  15. console.log(deepArry);
  16. deepArry[0] =5;
  17. console.log(a);
  18. console.log(deepArry);

运行的结果如下:
这里写图片描述

尝试多维数组

  1. var b = [[1,2,3],4,5];
  2. deepCopy(b,deepArry);
  3. console.log(b);
  4. console.log(deepArry);
  5. deepArry[0][1] =5;
  6. console.log(b);
  7. console.log(deepArry);

这里写图片描述

发现结果不能满足要求,按照上面函数的复制,数组的第二维还是存放着对之前数组的引用。
对函数进行优化后的代码:

  1. function deepCopy1(arry1, arry2){
  2.     var tempArry =[];
  3.     for(var i = 0,l= arry1.length;i<l;i++) {
  4.         //判断每一项是不是一个数组
  5.         if (arry1[i] instanceof Array ) {
  6.             deepCopy1(arry1[i], tempArry)
  7.             arry2[i] = tempArry;
  8.         }
  9.         else {
  10.             arry2[i] = arry1[i];
  11.         }
  12.     }
  13. }
  14. var b = [[1,2,3],4,5];
  15. var c = [[1,[2,3]],4,5];
  16. var d = [[1,2,3],4,[5,6,7]];
  17. var deepArray = [];
  18. deepCopy1(b, deepArry);
  19. console.log(deepArry);
  20. deepArry[0][0] =9;   //修改deepArry的值
  21. console.log(b);
  22. console.log(deepArry);
  23. deepArry.length=0;   //初始化deepArray
  24. deepCopy1(d,deepArry);
  25. console.log(deepArry);
  26. deepArry.length=0;
  27. deepCopy1(c,deepArry);
  28. console.log(c);
  29. console.log(deepArry);
  30. deepArry[0][1][0] = 99;
  31. console.log(c);
  32. console.log(deepArry);

运行结果如下:
这里写图片描述

对象的深拷贝

先来看一段代码:

  1. function Test(){
  2.     this.name='xiaohong',
  3.     this.age=18,
  4.     this.run =function(){
  5.         console.log('run');
  6.     }
  7. }
  8. var test = new Test();
  9. console.log(test.age);
  10. test.run();
  11. function ChilrTest () {
  12.     this.name = 'xiaogang',
  13.     this.age =15,
  14.     this.sing =function(){
  15.         console.log('sing');
  16.     }
  17. };
  18. ChilrTest.prototype =  new Test();
  19. var children = new ChilrTest();
  20. children.sing();
  21. children.run();
  22. console.log('----childre的属性----') ;
  23. for (var key in children){
  24.     console.log(key) ;
  25. }

结果为:

这里写图片描述

当我们使用for …in 遍历一个对象的时候他会向上查询原型链上得属性。

我们可以使用对象的hasOwnProperty属性来过滤掉原型链上得属性

  1. console.log('----childre的属性----') ;
  2. for (var key in children){
  3.     if(children.hasOwnProperty(key)) {
  4.         console.log(key);
  5.     }
  6. }

结果如下:

这里写图片描述

完整的clone一个对象的方法:

  1. var cloneObject ={};
  2. for (var key in children){
  3.     if(children.hasOwnProperty(key)) {
  4.         cloneObject[key] = children[key];
  5.     }
  6. }

使用js提供的方法深拷贝一维数组

  1. 使用slice函数
  2. var a =[1,2,3,4];
  3. var b =[];
  4. b =a.slice(0);
  5. console.log(b);
  6. b [0] = 9;
  7. console.log(a);
  8. console.log(b);

结果如下:

debugger listening on port 57289
[ 1, 2, 3, 4 ]
[ 1, 2, 3, 4 ]
[ 9, 2, 3, 4 ]

使用concat函数

  1. var a =[1,2,3,4];
  2. var b =[];
  3. //b =a.slice(0);
  4. b = a.concat([]);
  5. console.log(b);
  6. b [0] = 9;
  7. console.log(a);
  8. console.log(b);

结果如下:

debugger listening on port 57320
[ 1, 2, 3, 4 ]
[ 1, 2, 3, 4 ]
[ 9, 2, 3, 4 ]

jQuery中对数组的clone

使用jQuery进行对象的复制

  1. jQuery.extend( [ deep ], target , object1 [, objectN... ] )

请根据前面语法部分所定义的参数名称查找对应的参数。

参数描述
deep 可选/Boolean类型指示是否深度合并对象,默认为false。如果该值为true,且多个对象的某个同名属性也都是对象,则该”属性对象”的属性也将进行合并。
target Object类型目标对象,其他对象的成员属性将被复制到该对象上。 object1 可选/Object类型第一个被合并的对象。
objectN 可选/Object类型第N个被合并的对象。

示例代码:

  1. var a = { k1: 1, k2: 2, k3: 3 };
  2.   var b = {k4:4, k5:5};
  3.   var c ;
  4.   c=$.extend(a);           //将a对象复制到jquery对象上,并赋值给c
  5.   console.log('------------');
  6.   console.log(c === $);    //c对象指向的是$对象,所以结果true
  7.   console.log(a === $);   // false
  8.   console.log('------c------');
  9.   console.log(c.k2);       //相当于$.k2
  10.   console.log('------c------');
  11.   console.log(c);
  12.   //c.k2 = 777;
  13.   console.log('------a------');
  14.   console.log(a);
  15.   console.log('------b------');
  16.   console.log(b);
  17.   console.log('------$------');
  18.   console.log($);
  19.   console.log($.k2);

结果:
这里写图片描述
看下面的一段代码:
var d = $.extend({}, a)
console.log(d);
d.k2 = 3456;
console.log(d);
console.log(a);
结果为:
这里写图片描述

可以知道,jquery中extend()不是复制引用,而是创建了新的对象

注意事项:
该函数复制的对象属性包括方法在内。此外,还会复制对象继承自原型中的属性(JS内置的对象除外)。
参数deep的默认值为false,你可以为该参数明确指定true值,但不能明确指定false值。简而言之,第一个参数不能为false值。
如果参数为null或undefined,则该参数将被忽略。
如果只为$.extend()指定了一个参数,则意味着参数target被省略。此时,target就是jQuery对象本身。通过这种方式,我们可以为全局对象jQuery添加新的函数。
如果多个对象具有相同的属性,则后者会覆盖前者的属性值。

看下面一段代码对数组对象进行拷贝:

  1. var test = [1,2,34,];
  2. console.log(test);
  3. var contest= $.extend([],test);
  4. console.log(contest);
  5. contest.push(567);
  6. console.log(test);
  7. console.log(contest);

结果为:

这里写图片描述

 

ps 原文地址:http://blog.csdn.net/yisuowushinian/article/details/45544343

标签:

给我留言

Copyright © web前端技术开发个人博客 保留所有权利  京ICP备14060653号 Theme  Ality

用户登录