JavaScript 实现深拷贝

JavaScript 实现深拷贝 2014-08-27 17:27:56

分类: JavaScript



    写该系列的起因是在网上遇到一套比较不错的应试题目,涉及到了前端的各个角落,以及模块化,HTTP,后端等。题目在此前端题目

    第一题,就来讨论一下关于 JS 实现深拷贝的问题。

  1. var obj= { a: 1};
  2. var obj2= obj;

  3. obj2.a= 3;
  4. obj.a;// 3

    这是简单的对象引用,这仅仅是将对象的引用地址简单的复制了一份给予变量 obj2,而并不是将真正的对象克隆了一份,原对象依旧是只有一个。影响则为,当我修改 obj2 内部的属性或者添加新属性时会影响 obj ,因为两个变量的值为同一个对象的地址引用,即两者指向的是同一个对象。

    这就是所谓深拷贝的意义所在,不是拷贝引用地址,而是实实在在的复制一份新对象。而目前标准中还未提供一个类似的原生方法(主要是由于需求不大,JS 本身已经可以处理的很好了)。所以对于深拷贝,主要遇到的问题就是对于数组,对象以及方法的复制。


    对象一般来说不考虑原型链上对象的属性,均是使用 for in 遍历并且使用,由于浏览器的五花八门,还需要使用 hasOwnPrototype 来进行过滤下。当然也需要考虑某属性值为 对象,数组,函数等情况。

    数组:对于数组来说,也可以如对象一样 for in 循环遍历,不过通常情况是使用长度进行循环,对空数组进行不断的 push。

    函数:对于一般库来说,一些深拷贝函数基本都不进行处理,实在需要处理的可以调用函数的 toString,再使用 eval  或者 Function 进行处理,得到新的函数。

    然后上个实例吧,是自己正在写的库中的简单的一个拷贝方法 mix,由于库的原因扩展了一些功能以及对于方法不做复制处理,使用外部的一个方法 type,是用来判断区分类型,如 array object function。


  1. /** 对象扩展 mix
  2.   *
  3.   * @method mix 不扩展原型属性
  4.   * @param {obj} receiver 可选 扩展的目标对象 如果无 则扩展到外围对象
  5.   * @param {obj} obj 必选 要扩展到目标对象的对象数据
  6.   * @param {boolean} ride 可选 主要是标识是否覆盖原有对象属性 默认为true
  7.   * @param {boolean} deep 可选 主要是标识是否需要简单的深度拷贝 默认为false
  8.   *
  9.   * @return {Object} 返回目标对象
  10.   *
  11.   */
  12.   var hasOwn = Object.prototype.hasOwnProperty;
  13.   function mix(receiver, obj){
  14.       var args= [].slice.call(arguments),key, i= 1deep, ride,value, valueType;

  15.       if(typeof args[args.length-2]==="boolean" ){
  16.           deep = args.pop();
  17.           ride = args.pop();
  18.       }else{
  19.           ride =(typeof args[args.length-1]==="boolean")?args.pop():true;
  20.           deep =false;
  21.           if(args.length< 2){
  22.               receiver = ( this !==global ) ? this : {};
  23.               if( args.length=== 0){
  24.                   return receiver;
  25.               }
  26.           }
  27.       }

  28.       while( obj= args[ i++] ){
  29.           for(key in obj ){
  30.               if( hasOwn.call(obj,key)){
  31.                   if( ride|| !(keyin receiver)){
  32.                       value= obj[key];
  33.                       valueType= type(value);
  34.                       if( deep&&( valueType==="object")){
  35.                           receiver[key]={};
  36.                           mix(receiver[key],value, ride, deep);
  37.                       }elseif( deep&&( valueType==="array")){
  38.                           receiver[key]=[];
  39.                           mix(receiver[key],value, ride, deep);
  40.                       }else{
  41.                           receiver[key]= obj[key];
  42.                       }
  43.                   }
  44.               }
  45.           }
  46.       }
  47.       return receiver;
  48.   }


对于 type 函数,源代码如下

  1. // 类型判定对象
  2. var class2type= {
  3.     "[objectHTMLDocument]": "document",
  4.     "[objectHTMLCollection]": "nodeList",
  5.     "[objectStaticNodeList]": "nodeList",
  6.     "[objectIXMLDOMNodeList]": "nodeList",
  7.     "null": "null",
  8.     "NaN": "NaN",
  9.     "undefined": "undefined"
  10. };

  11. "Boolean, Number, String, Function, Array, Date, RegExp, Document, Arguments, NodeList"
  12.     .replace/[^, ]+/g,function(type ){
  13.         class2type["[object "+ type + "]"] = type.toLowerCase();
  14.     });

  15. // 类型判定
  16. function type( obj, isType){
  17.     varkey = ((obj==null || obj!== obj) ? obj +"" : Object.prototype.toString.call( obj )),
  18.         result;
  19.     
  20.     if(typeof(result= class2type[key ]) !=="string" ){
  21.         if( obj.nodeType=== 9){
  22.             result = class2type["Document"];
  23.         }elseif( obj.item&&typeof obj.length==="number" ){
  24.             result = class2type["NodeList"];
  25.         }else{
  26.             result =key.slice(8,-1);
  27.         }
  28.     }


  29.     if( isType){
  30.         return result=== isType.toLowerCase;
  31.     }


  32.     return result;
  33. }


这就是简单的对于 JS 实现深拷贝的例子,有什么错误,欢迎指出。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值