首页 > 代码库 > ife2015 深度克隆题目

ife2015 深度克隆题目

今天在做2015ife的题时,感觉收获很多,对于js基本类型有了新的认识。把在研究过程中所得记录下来! 
题目是:

// 使用递归来实现一个深度克隆,可以复制一个目标对象,返回一个完整拷贝 
// 被复制的对象类型会被限制为数字、字符串、布尔、日期、数组、Object对象。不会包含函数、正则对象等

首先要去判断要克隆的对象的值类型或者引用类型。判断方法有很多种! 
对于值类型或者引用有4种方法判断

1.typeof

但是!js的数值有两种构造方法:直接赋值法和通过值函数构造器构造 
例如: 
var test1 = "string"; 
var test2 = new String("string2"); 
console.log(typeof test1);//输出string 
console.log(typeof test2);//输出object
 
对于typeof来说;所有通过构造器constructor产生的变量都是object.那么我们怎么去判断用constructor产生的变量?

2.instanceof

instanceof 函数可以判断左边参数是否是右边参数的一个实例! 
例如: 
console.log(test2 instanceof String);//输出true 
但是! 
console.log(test1 instanceof String);//输出false 
这就很不和谐了!有没有两种都能判断的方法呢?

3.Object.prototype.toString.call()

当然有!MDN在官方教程上就介绍了一种可以判断所有类型的方法! 
使用toString()方法来检测对象类型

console.log(Object.prototype.toString.call(test1))//输出[object String] 
console.log(Object.prototype.toString.call(test1))//输出[object String]
 
顿时觉得人生豁然开朗了起来!啊~五环!你比四环多一环!

4.Object.constructor

在研究MDN 的api文档的时候,发现了constructor方法!However这个方法 
返回一个指向创建了该对象原型的函数引用。需要注意的是,该属性的值是那个函数本身, 
而不是一个包含函数名称的字符串! 
而不是一个包含函数名称的字符串!! 
而不是一个包含函数名称的字符串!!! 
对于原始值(如1,true 或 “test”),该属性为只读。 
所有对象都会从它的原型上继承一个 constructor 属性. 
所以,虽然可以实现判断,但是还是不用为好! 
console.log(test1.constructor.toString()=="function String() { [native code] }")//true; 
console.log(test2.constructor.toString()=="function String() { [native code] }")//true;
 
总结:方法34对于所有值类型和引用类型适用(推荐第三种方法,毕竟官方),第12种方法看情况使用!

然后来到遍历问题了! 
1.字符串的遍历

`
     var temp = src.split("");
        var cloneString="";
        for(var i=0;i<temp.length;i++)
        {
             cloneString+=temp[i];
             }

`
原理就是利用split方法将字符串里一个个字母分开(注意里面的参数为空"",为其他就会以这个参数为标准分离字符串)

2.数组的遍历 
使用的是传统的数组遍历

var temp = new Array();
    for(var i=0,a;a = array[i];i++)
    {
         temp[i] = cloneObject(a);
    }

这里遇到了几个坑,先说一下: 
当使用 
for(var a in array) 
{console.log(a+typeof a)} 
得到的值是 
0 string 
1 string 
2 string 
这种方法并不行 
还有一个坑就是当使用 
for(var i=0,a;a = array[i++];)时 
i会在a被赋值后就自动增加而不是等到一个循环完成再增加 
;也就是遍历结果是对的,但是i的数值变化是从1开始而不是从0开始的! 
在赋值的过程中,我首先使用的是temp.push()方法!但是!push方法会让 
temp数组新增加的元素的类型为undefined!这不是我想要的结果!我要的是完美克隆,即数组里面对象类型也要和原来的一致。看了MDN的api接口发现解决方法如下: 
Array.prototype.push.apply(temp,array); 
3.对象的遍历

 var temp = {}; 
            var keys = Object.keys(src);
            // keys 为对象src的键名字数组
            // 它是数组!!!
            for(var i=0,a;a=keys[i];i++)
            {
                temp[a] = cloneObject(src[a]);
            }

对象的遍历,首先获得它的键数组(对象自带的keys()方法),然后再通过键遍历一次值就行了,很简单。

心得:ife的题真的很能锻炼基础。感谢百度前端技术学院!(这波广告我给自己88分)!多看MDN总会有收获!下面附上我的代码!(请无视里面的吐槽注释还有一些小白的地方)

var cloneObject = function(src){
    var Result;
    switch(Object.prototype.toString.call(src)){
        case "[object Number]": 
            Result = (typeof src =http://www.mamicode.com/=="object"?new Number(src):parseInt(src.toString()));
            break;
        case "[object String]":
            // 遍历字符串 =.= 好像没啥意义
            // {
            //  var temp = src.split("");
            //  var cloneString="";
            //  for(var i=0;i<temp.length;i++)
            //  {
            //      cloneString+=temp[i];
            //  }
            // }
            Result = (typeof src =http://www.mamicode.com/=="object"?new String(src):src.toString());
            break;
        case "[object Boolean]":
            Result = (typeof src =http://www.mamicode.com/=="Boolean"?new Boolean(src):src);
            break;
        case "[object Date]":
            Result = new Date(src);
            break;
        case "[object Array]":
            var temp = new Array();
              // Array.prototype.push.apply(temp,src);
             // 当使用for(var i=0,a;a = src[i++];) i会在a被赋值后就自动增加而不是
             // 等到一个循环完成再增加
            for(var i=0,a;a = src[i];i++)
            {
                  // temp.push(cloneObject(a));
                  // 使用push方法会让数组所有元素的类型变成undfined
                 temp[i] = cloneObject(a);
            }
            Result = temp;
            delete temp;
            break;
        case "[object Object]":
            var temp = {}; 
            var keys = Object.keys(src);
            // keys 为对象src的键名字数组
            // 它是数组!!!
            for(var i=0,a;a=keys[i];i++)
            {
                temp[a] = cloneObject(src[a]);
            }
            Result = temp;
            delete temp;
            delete keys;
            break;
        default:
            break;
    }
    return Result;
}

 

 
 

ife2015 深度克隆题目