javascript关于对象深拷贝和数组去重的问题...

http://www.cnblogs.com/hongru/archive/2010/09/24/1833928.html


中秋最后一天假期,还是憋屈在家里,没事可做,发发关于两个看似很基础却又很有意义的两个问题的一点感想,如题...

一.对象深拷贝:

对应的浅拷贝,对象是通过地址指向来获得引用的,所以单纯的用一个新对象指向源对象就是浅拷贝,对新对象的操作同样会影响的源对象。好比小明有个U盘,里面装有一些资料,一天,小红也需要这个U盘里的资料,于是拿过来改了里面的资料,结果小明再用时,里面资料就变了,因为两个人用的其实是同一个u盘嘛... 如下:

 

1
2
3
4
5
var obj = {a: 'a' };
var obj1 = obj;
obj.a = 'a1' ;
alert(obj.a);
alert(obj1.a);

运行

那么怎么样才能资料各自私有而不影响对方呢,显而易见嘛,让小红也去买个u盘,并把资料也拷一份到她的u盘里,各用个的就行了。于是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function clone(myObj)
{
     if ( typeof (myObj) != 'object' || myObj == null ) return myObj;
     var myNewObj = new Object();
     for ( var i in myObj) myNewObj[i] = clone(myObj[i]); //递归调用,当对象中又有对象时
     return myNewObj;
}
var obj = {a: 'a' };
var obj1 = obj;
var obj2 = clone(obj);
obj.a = 'a1' ;
alert(obj.a);
alert(obj1.a);
alert(obj2.a);

运行

至此,区别也很明显了,obj1浅拷贝由于是访的同一个对象,故改变源对象obj,新对象obj1也随之改变。而深拷贝obj2是新建了一个对象实例,与源对象obj互不干扰。

 

二.关于数组去重

网上很流行一种解法,如下:

1
2
3
4
5
6
7
8
9
10
Array.prototype.filter = function (){
     for ( var i=0,temp={},result=[],ci;ci= this [i++];){
         if (temp[ci]) continue ;
         temp[ci]=1;
         result.push(ci);
     }
     return result;
}
var aa=[ '1' , '2' , '3' , '1' , '2' ];
alert(aa.filter());

运行

它其实是用了对象的特性,把每个数组元素当做一个对象的属性来判断是否存在,这样做有个好处是不用二次遍历数组。然而,乍一看结果没问题,可是一旦数组里有了number,布尔值,对象等作为元素的时候,就会发现问题了。
原因在于:对象则要求其属性值必须为字符串,如果提供给对象的属性不是字符串,那么则会自动调用 toString 方法转化为字符串形式,于是,严格来讲,这种方法只能在数组元素全为字符串时才成立

我们再看看jquery的源码是怎么实现数组去重的方法的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
unique: function ( array ) { 
         var ret = [], done = {}; 
         try
             for ( var i = 0, length = array.length; i < length; i++ ) { 
                 var id = jQuery.data( array[ i ] ); 
   
                 if ( !done[ id ] ) { 
                     done[ id ] = true
                     ret.push( array[ i ] ); 
                
            
   
         } catch ( e ) { 
             ret = array; 
         }  
         return ret; 
     }, 

乍一看,其实思路跟我上面说的方法是一样的,可是别忘了很重要的一点,var id = jQuery.data( array[ i ] );这一句,其实是把每个数组元素都转换成了节点数组再做的判断。

所以,如果把安全性放在首位,效率次之的话,数组去重还是应该老老实实二次遍历数组,如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
functionundulpicate(array){ 
    for(vari=0;i<array.length;i++) { 
        for(varj=i+1;j<array.length;j++) { 
            //注意 === 
            if(array[i]===array[j]) { 
                array.splice(j,1); 
                j--; 
            
        
    
    returnarray; 
}

 

当然,如果能确定数组元素类型,大可不必这样做,毕竟二次遍历在数据量大的时候是个不小的消耗。。
此外,貌似hash查找可以减少一次遍历...具体还没想过...唉,今天就到此位置吧


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值