javascript代码实例教程-javascript中对象的深度克隆

发布时间:2019-01-25 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了javascript代码实例教程-javascript中对象的深度克隆脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
小宝典致力于为广大程序猿(媛)提供高品质的代码服务,请大家多多光顾小站,小宝典在此谢过。 又是一个月多月没有更新博客了,这段时间回学校处理下论文的事情,实习的生活也暂时告一段落(在公司上班,才发现学校里面的生活简直如天堂一般,相信很多已经毕业的小伙伴肯定被我说中了,说中了请给本文点个赞,哈哈!)。希望接下来自己的更新进度能加快,马上又是一年校招时,被虐也好、大牛虐别人也罢,总之祝福各位今年要找工作的小伙伴们好运。那么,今天就聊一下一个常见的笔试、面试题,js中对象的深度克隆。翻了下这个题目,在很多地方出现过,已经算一个老的题目了,但是每年的校招中总会考到,其实想想,这个题目考查的知识点还是蛮多的,尤其是对基础知识的考查。好了,闲话不多说,开始正题。

 

一、js中的对象

 

谈到对象的克隆,必定要说一下对象的概念。

 

js中的数据类型分为两大类:原始类型和对象类型。(1)原始类型包括:数值、字符串、布尔值、null、undefined(后两个是特殊的原始值,这里不做详细的说明,我的上一篇博客有谈到过一些)(2)对象类型包括:对象即是属性的集合,当然这里又两个特殊的对象----函数(js中的一等对象)、数组键值的有序集合)。

 

好了既然对象分为这两类,这两种类型在复制克隆的时候是有很大区别的。原始类型存储的是对象的实际数据,而对象类型存储的是对象的引用地址(对象的实际内容单独存放,为了减少数据开销通常存放在内存中)。ps:说到这里,大家要知道,对象的原型也是引用对象,它把原型的方法和属性放在内存当中,通过原型链的方式来指向这个内存地址。

 

二、克隆的概念

 

浅度克隆:原始类型为值传递,对象类型仍为引用传递。

 

深度克隆:所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象中。

 

三、浅克隆的表现

 

1,原始类型

 

看下面一段代码:

 

复制代码

//数值克隆的表现

VAR a="1";

var b=a;

b="2";

console.LOG(a);// "1"

console.log(b);// "2"

 

//字符串克隆的表现

var c="1";

var d=c;

d="2";

console.log(c);// "1"

console.log(d);// "2"

 

//字符串克隆的表现

var x=true;

var y=x;

y=false;

console.log(x);// true

console.log(y);// false

复制代码

从上面的代码大家可以看出,原始类型即使我们采用普通的克隆方式仍能得到正确的结果,原因就是原始类型存储的是对象的实际数据。

 

2.对象类型

 

前面说过,函数式一等对象,当然也是对象类型,但是函数的克隆通过浅克隆即可实现

 

复制代码

var m=function(){alert(1);};

var n=m;

n=function(){alert(2);};

 

console.log(m());//1

console.log(n());//2

复制代码

大家能看到,我们直接通过普通赋值的方式,就实现了函数的克隆,并且不会影响之前的对象。原因就是函数的克隆会在内存单独开辟一块空间,互不影响

 

好了,说了这个特殊的”关系户“以后,我们来说说普通的”选手“。为了方便后续的代码表现,我这里定义一个复杂的对象类型oPErson。下面看一下对象类型的浅复制有什么危害

 

复制代码

var oPerson={

    oName:"rookiebob",

    oAge:"18",

    oAddress:{

        PRovince:"beijing"

    },    

    ofavorITe:[

        "swimming",

        {reading:"history Book"}

    ],

    skill:function(){

        console.log("bob is coding");

    }

};

function clone(obj){

    var result={};

    for(key in obj){

        result[key]=obj[key];

    }

    return result;

}

var oNew=clone(oPerson);

console.log(oPerson.oAddress.province);//beijing

oNew.oAddress.province="shanghai";

console.log(oPerson.oAddress.province);//shanghai

复制代码

通过上面的代码,大家能看到,经过对象克隆以后,我修改oNew的地址,发现原对象oPerson也被修改了。这说明对象的克隆不够彻底,那也就是说深度克隆失败!

 

四、深克隆的实现

 

为了保证对象的所有属性都被复制到,我们必须知道如果for循环以后,得到的元素仍是Object或者Array,那么需要再次循环,直到元素是原始类型或者函数为止。为了得到元素的类型,我们定义一个通用函数,用来返回传入对象的类型。

 

复制代码

//返回传递给他的任意对象的类

function isClass(o){

    if(o===null) return "Null";

    if(o===undefined) return "Undefined";

    return Object.prototype.toString.call(o).slice(8,-1);

}

复制代码

PS:Object.prototype.toString.call(o)能直接返回对象的类属性,形如"[object class]"的字符串,我们通过截取class,并能知道传入的对象是什么类型。

 

当然这里有两个疑问需要解释下:

 

(1)为什么不直接用toString方法?这是为了止对象中的toString方法被重写,为了正确的调用toString()版本,必须间接的调用Function.call()方法

 

(2)为什么不使用typeof来直接判断类型?因为对于Array而言,使用typeof(Array)返回的是object,所以不能得到正确的Array,这里对于后续的数组克隆将产生致命的问题。

 

万事俱备,只欠曹操了,下面就正儿八经的开始克隆。

 

复制代码

//深度克隆

function deepClone(obj){

    var result,oClass=isClass(obj);

        //确定result的类型

    if(oClass==="Object"){

        result={};

    }else if(oClass==="Array"){

        result=[];

    }else{

        return obj;

    }

    for(key in obj){

        var copy=obj[key];

        if(isClass(copy)=="Object"){

            result[key]=arguments.callee(copy);//递归调用

        }else if(isClass(copy)=="Array"){

            result[key]=arguments.callee(copy);

        }else{

            result[key]=obj[key];

        }

    }

    return result;

}

//返回传递给他的任意对象的类

function isClass(o){

    if(o===null) return "Null";

    if(o===undefined) return "Undefined";

    return Object.prototype.toString.call(o).slice(8,-1);

}

var oPerson={

    oName:"rookiebob",

    oAge:"18",

    oAddress:{

        province:"beijing"

    },    

    ofavorite:[

        "swimming",

        {reading:"history book"}

    ],

    skill:function(){

        console.log("bob is coding");

    }

};

//深度克隆一个对象

var oNew=deepClone(oPerson);

 

oNew.ofavorite[1].reading="picture";

console.log(oNew.ofavorite[1].reading);//picture

console.log(oPerson.ofavorite[1].reading);//history book

 

oNew.oAddress.province="shanghai";

console.log(oPerson.oAddress.province);//beijing

console.log(oNew.oAddress.province);//shanghai

复制代码

从上面的代码可以看到,深度克隆的对象可以完全脱离原对象,我们对新对象的任何修改都不会反映到原对象中,这样深度克隆就实现了。

 

这里要注意一点的就是:为什么deepClone这个函数中的result一定要判断类型?这里有一种情况,如果你的result直接是{}对象,我明明传进去的是一个数组,结果你复制完了以后,变成了一个对象了。

 

复制代码

//深度克隆

function deepClone(obj){

    var result={},oClass=isClass(obj);

    // if(oClass==="Object"){

    //     result={};

    // }else if(oClass==="Array"){

    //     result=[];

    // }else{

    //     return obj;

    // }

    for(key in obj){

        var copy=obj[key];

        if(isClass(copy)=="Object"){

            result[key]=arguments.callee(copy);

        }else if(isClass(copy)=="Array"){

            result[key]=arguments.callee(copy);

        }else{

            result[key]=obj[key];

        }

    }

    return result;

}

function isClass(o){

    if(o===null) return "Null";

    if(o===undefined) return "Undefined";

    return Object.prototype.toString.call(o).slice(8,-1);

}

//克隆一个数组

var arr=["a","b","c"];

var oNew=deepClone(arr);

console.log(oNew);//Object {0: "a", 1: "b", 2: "c"} 

觉得可用,就经常来吧! 脚本宝典 欢迎评论哦! js脚本,巧夺天工,精雕玉琢。小宝典献丑了!

脚本宝典总结

以上是脚本宝典为你收集整理的javascript代码实例教程-javascript中对象的深度克隆全部内容,希望文章能够帮你解决javascript代码实例教程-javascript中对象的深度克隆所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。