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

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

一.对象深拷贝:

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

var obj = {a:'a'};
var obj1 = obj;
obj.a = 'a1';
alert(obj.a);
alert(obj1.a);

运行

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

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互不干扰。

二.关于数组去重

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

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的源码是怎么实现数组去重的方法的:

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 ] );这一句,其实是把每个数组元素都转换成了节点数组再做的判断。

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

function undulpicate(array){  
    for(var i=0;i<array.length;i++) {  
        for(var j=i+1;j<array.length;j++) {  
            //注意 ===  
            if(array[i]===array[j]) {  
                array.splice(j,1);  
                j--;  
            }  
        }  
    }  
    return array;  
} 

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

原文地址:https://www.cnblogs.com/hongru/p/1833928.html