javascript clone

<a href="http://bbs.51js.com/forum.php?mod=viewthread&tid=74167&extra=pageD1%3D&page=1">ref</a>
<pre>
1.基本类型string boolean undefined null number皆可直接用=赋值
2.普通object clone
//最简单clone
function objectClone(){
	var ret=new Object();
	for(var p in this){
		ret[p]=this[p];
	}
	return ret;
}
//deep clone
function objectDeepClone(){
	var ret=new Object();
	for(var p in this){
		if(typeof this[p]!=object){
			ret[p]=this[p];
		}else{ 
			ret[p]=objectDeepClone.call(this[p]);
		}
	}
	return ret;
}
//利用构造器prototype属性赋值进行clone
function objectPrototypeClone(){
	var tmp=function(){};
	tmp.prototype=this;
	return new tmp;
}

这样clone出来的对象只读地共享一个原型的属性,它的最大优势是速度非常快,当我们希望快速复制大型对象时,可以使用这种方式,<blockquote>但是它会造成访问速度降低,而且它实时反映父节点的变化。</blockquote>
3.内置对象的clone
3.1Function
对Function来说,完全产生一个副本是不可能的,因为我们无法保证构造的函数跟原来的函数在同一作用域,但是不包含作用域的实现是很容易的:eval(this);或者使用Function构造 return Function(new String("return ")+this)();
Function本身是个Object 因此必须加上Object的clone 实现functionPrototypeClone需要一点小花招
function functionDeepClone(){
	var ret=Function(new String("return ")+this)();
	for(var p in this){
		if(typeof this[p]!=object){
			ret[p]=this[p];
		}else{
			ret[p]=objectDeepClone.call(this[p]);
		}
	}
	return ret;
}
//原型clone
function functionPrototypeClone(){                
	var tmp=Function.prototype;//备份
	Function.prototype=this;//改变原型
	var ret=(new Function(new String("return ")+this))();
	Function.prototype=tmp;//恢复原型
	return ret;
}

3.2Array
function arrayDeepClone(){
	var ret=new Array();
        //用for in考虑var a = [1,2,3];a["x"] = 100;这种情况 arrObj.slice(0)就有问题
	for(var p in this){
		if(typeof this[p]!=object){
			ret[p]=this[p];
		}else{
			ret[p]=objectDeepClone.call(this[p]);
		}
	}
	return ret;
} 
function arrayPrototypeClone(){                
	var tmp=Array.prototype;
	Array.prototype=this;
	var ret=new Array();
	Array.prototype=tmp;
	return ret;
}
//其他的一些实现arrayClone的方法,如:
function(){
    return Array.apply([],this);
}

function(){
    return [].concat(this);
}

3.3Date
function dateDeepClone(){
	var ret=new Date();
	ret.setTime(this.getTime());
	for(var p in this){
		if(typeof this[p]!=object){
			ret[p]=this[p];
		}else{
			ret[p]=objectDeepClone.call(this[p]);
		}
	}
	return ret;
} 
function datePrototypeClone(){                
	var tmp=Date.prototype;
	Date.prototype=this;
	var ret=new Date();
	ret.setTime(this.getTime());
	Date.prototype=tmp;
	return ret;
}

3.4String Boolean Number都是只读的对象,所以只要=就可以了
3.5完整的clone

function clone(){
	var ret;
	if(this instanceof Function){
		ret=Function(new String("return ")+this)();
	}else if(this instanceof Array){
		ret=new Array();
	}else if(this instanceof Date){
		ret=new Date();
		ret.setTime(this.getTime());
	}else if( (this instanceof String) || (this instanceof Boolean) || (this instanceof Number) ){
		return this;
	}else{
		ret=new Object();
	}
	
	for(var p in this){
		ret[p]=this[p];
	}
	
	return ret;
}

function deepClone()
{
	var ret;
	if(this instanceof Function){
		ret=Function(new String("return ")+this)();
	}else if(this instanceof Array){
		ret=new Array();
	}else if(this instanceof Date){
		ret=new Date();
		ret.setTime(this.getTime());
	}else if( (this instanceof String) || (this instanceof Boolean) || (this instanceof Number) ){
		return this;
	}else{
		ret=new Object();
	}

	for(var p in this){
		if(typeof this[p]!=object){
			ret[p]=this[p];
		}else{
			ret[p]=objectDeepClone.call(this[p]);
		}
	}
	return ret;
}
function prototypeClone(){
	if(this instanceof Function){
		var tmp=Function.prototype;
		Function.prototype=this;
		var ret=(new Function(new String("return ")+this))();
		Function.prototype=tmp;
		return ret;
	}else if(this instanceof Array){
		var tmp=Array.prototype;
		Array.prototype=this;
		var ret=new Array();
		Array.prototype=tmp;
		return ret;
	}else if(this instanceof Date){
		var tmp=Date.prototype;
		Date.prototype=this;
		var ret=new Date();
		ret.setTime(this.getTime());
		Date.prototype=tmp;
		return ret;
	}else if( (this instanceof String) || (this instanceof Boolean) || (this instanceof Number) ){
		return this;
	}else{
		var constructor=function(){};
		constructor.prototype=this;
		return new constructor;
	}
}

   前面讨论了三种Clone的实现方法,它们各自具有适合的语义环境,比如对一个数组来说 若是把它理解为一个集合Collection 则应该使用浅clone(假如集合A是B的子集,则应保证A.clone()亦是B的子集),若是把它理解为一个向量Vector,则应使用深clone(保证对向量A的分量操作不应影响向量A.clone()的分量)。prototypeClone的一个最常见的应用场景是深度优先搜索算法算法,为了扩展解空间树,我们通常需要快速的构造一个副本,如果使用clone或者deepClone 这将非常慢,而深度优先搜索的特点是在字节点被销毁之前,父节点不会变化,所以prototypeClone是非常合适的。

附:Prototype-oriented Programming和Prototype Pattern
面向原型的语言思想跟原型模式是完全一致的:从同一原型clone出来的对象就是一类对象。Prototype-oriented的语言对这种模式提供了语言级别的支持,即所有"类"的定义都是通过指定该类的一个原型来实现的(Class-Based Programming是通过类结构声明来描述一类对象,meta-class则是通过构造一个"类对象"来描述一类对象)。每次实例话就clone一次原型,然而这种方式会造成信息的冗余:所有对象都持有原型对象的一个clone的副本,而且一旦某一对象被构造,修改原型不会对它造成任何影响,这对于希望在程序中统一改变某一类对象的人来说很不方便。于是,一种变通的方法产生了:引用型原型对象,与之相对,原来的原型对象使用方法被称为 复制型原型对象。引用型原型对象不再clone原型,而是保存一个指向原型的指针,当访问属性时,首先检查自己的属性,当查到不存在时,则通过指针向原型索取相应属性。而引用型原型就是javascript的面向原型特性的实现方式。
</pre>

你可能感兴趣的:(JavaScript,prototype,clone)