JS为什么要克隆json对象

JavaScript017

JS为什么要克隆json对象,第1张

如果你想根据一个json对象再创建一个新的对象,你可能第一时间会想到把这个json对象直接赋值给一个对象变量即可,真的如此吗?不!这个变量获得的只不过是这个json对象的指针(或者说内存地址),也就是说它们其实仍然是同一个对象,修改这个变量的某个属性值,原来的那个对象也会跟着改变,就好比一个人办了两张不同的身份证,尽管身份证不同,但持有这两张身份证的仍然是同一个人!这种情况下就要用到对象克隆了,也就是把原对象在内存中重新复制一份,然后把新的指针赋值给另一个变量,这样的话,两个对象就不再是同一个了,尽管它们内容相同,但你修改其中一个,另一个不会受其影响了。

具体做法就是新建一个空的对象,然后把原来的json对象的所有属性和方法一个个复制到新的对象中即可。

要实现深复制有很多办法,比如最简单的办法有:

var cloneObj = JSON.parse(JSON.stringify(obj))

上面这种方法好处是非常简单易用,但是坏处也显而易见,这会抛弃对象的constructor,也就是深复制之后,无论这个对象原本的构造函数是什么,在深复制之后都会变成Object。另外诸如RegExp对象是无法通过这种方式深复制的。

所以这里我将介绍一种,我自认为很优美的深复制方法,当然可能也存在问题。如果你发现了我的实现方法有什么问题,请及时让我知道~

先决条件:

1. 对于任何对象,它可能的类型有Boolean, Number, Date, String, RegExp, Array 以及 Object(所有自定义的对象全都继承于Object)

2. 我们必须保留对象的构造函数信息(从而使新对象可以使用定义在prototype上的函数)

最重要的一个函数:

Object.prototype.clone = function () {

var Constructor = this.constructor

var obj = new Constructor()

for (var attr in this) {

if (this.hasOwnProperty(attr)) {

if (typeof(this[attr]) !== "function") {

if (this[attr] === null) {

obj[attr] = null

}

else {

obj[attr] = this[attr].clone()

}

}

}

}

return obj

}

定义在Object.prototype上的clone()函数是整个方法的核心,对于任意一个非js预定义的对象,都会调用这个函数。而对于所有js预定义的对象,如Number,Array等,我们就要实现一个辅助clone()函数来实现完整的克隆过程:

/* Method of Array*/

Array.prototype.clone = function () {

var thisArr = this.valueOf()

var newArr = []

for (var i=0i<thisArr.lengthi++) {

newArr.push(thisArr[i].clone())

}

return newArr

}

/* Method of Boolean, Number, String*/

Boolean.prototype.clone = function() { return this.valueOf()}

Number.prototype.clone = function() { return this.valueOf()}

String.prototype.clone = function() { return this.valueOf()}

/* Method of Date*/

Date.prototype.clone = function() { return new Date(this.valueOf())}

/* Method of RegExp*/

RegExp.prototype.clone = function() {

var pattern = this.valueOf()

var flags = ''

flags += pattern.global ? 'g' : ''

flags += pattern.ignoreCase ? 'i' : ''

flags += pattern.multiline ? 'm' : ''

return new RegExp(pattern.source, flags)

}

可能直接定义在预定义对象的方法上,让人感觉会有些问题。但在我看来这是一种优美的实现方式。

同时我也在开发一个插件,主要的思想也就是扩展预定义对象的方法。

这个插件叫JustJS(Github项目地址)

有以下一些特性:

1. 同时支持Web前端和node.js使用。

2. 直接对预定义对象的方法进行扩展

3. 使用 J(function(){...}) 语句块,决不污染全局命名空间。

目前只写了一小部分,同时也写了些简单的文档,有兴趣的同学可以看一下,也可以加入我,Fork我的项目,喜欢的同学还可以给Star!

如果是使用了  JQ  EXTJS 的话本身就有 对象克隆的 函数库可以使用  如 extjs 使用

ext.ux.util.clone()

没有用这些的话 可以自己写一个 克隆函数  网上有资源  比如

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)

}

或者参考 extjs 的方法

 function(o) {  

   if(!o || 'object' !== typeof o) {        return o    }   

    if('function' === typeof o.clone) {        return o.clone()    }   

     var c = '[object array]' === object.prototype.tostring.call(o) ? [] : {}

     var p, v    

     for(p in o) {       

      if(o.hasownproperty(p)) {            v = o[p]           

      if(v && 'object' === typeof v) {               

       c[p] = ext.ux.util.clone(v)          

         }     else {          

               c[p] = v          

           }        

           }   

            }  

        return c}