Chinaunix首页 | 论坛 | 博客
  • 博客访问: 241382
  • 博文数量: 43
  • 博客积分: 391
  • 博客等级: 二等列兵
  • 技术积分: 352
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-17 11:29
个人简介

现在的我,不埋怨谁,不嘲笑谁,也不羡慕谁。阳光下灿烂,风雨中奔跑,做自己的梦,走自己的路。一切都好,真的,都很好。

文章分类

全部博文(43)

文章存档

2018年(2)

2017年(1)

2015年(2)

2014年(27)

2013年(1)

2012年(10)

我的朋友

分类: JavaScript

2014-09-04 00:19:40

原文地址:JavaScript 实现深拷贝 作者:lovenyf



    写该系列的起因是在网上遇到一套比较不错的应试题目,涉及到了前端的各个角落,以及模块化,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 || !(key in 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.                       }else if( 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.     var key = ((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.         }else if( 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 实现深拷贝的例子,有什么错误,欢迎指出。







阅读(724) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~