一种基于ES5的JavaScript继承

关于JavaScript继承,方式非常多,包含compile-to-javascript的语言TypeScript, CoffeeScript以及站点MDN, GitHub, Modernizr各种polyfill都给出了稳妥的实现方案。
从ES5的角度看,这当中一些方案在功能上OK,但在语义上却不尽如人意。
本人从这些方案中採取一些比較潮的思路,整理出一份方案,可实现与原生DOM类继承的风格一致,达到功能和语义兼得的效果(当然,就别再老想着99后ES3了)。
假设你的WebApp是基于ES5执行环境的,能够评估或fork此方案。

//exports Function.prototype.extends
//exports global.getPrototypeNames

//基于ES5的继承实现函数
Function.prototype.extends=(function(){
	function getOwnPropertyDescriptors(object){
		return Object.getOwnPropertyNames(object).reduce(function(pds,pn){
			return pds[pn]=Object.getOwnPropertyDescriptor(object,pn),pds;
		},{});
	}
	/**
	 * 继承一个类。
	 * 若有兴许类,则共享兴许类截至到当前的快照属性(constructor除外),
	 * 这些属性中的getters,setters和methods须考虑到要是通用的(如Array的那些methods)
	 **/
	function inherits(s){
		var c,p;
		c=this;
		if(typeof s==="function"){
			p=Object.create(s.prototype,getOwnPropertyDescriptors(c.prototype));
		}else{
			p=c.prototype;
		}
		if(arguments.length>1){
			Array.prototype.slice.call(arguments,1).forEach(function(s){
				var pds=getOwnPropertyDescriptors(s.prototype);
				delete pds.constructor;
				Object.defineProperties(p,pds);
			});
		}
		c.prototype=p;
	}
	return inherits;
}());



//測试准备
//~~~~~~~~~~~~~~~~~~~~~~~~
// BaseList extends Array
//~~~~~~~~~~~~~~~~~~~~~~~~
function BaseList(){
	this.length=this.length;
}
BaseList.prototype.add=function(e){
	return this.push(e);
};
BaseList.extends(Array);

//~~~~~~~~~~~~~~~~~~~~~~~~
// ItemList extends BaseList
//~~~~~~~~~~~~~~~~~~~~~~~~
function ItemList(){
	BaseList.call(this);
}
ItemList.extends(BaseList,EventTarget);
ItemList.prototype.item=function item(index){
	index>>>=0;
	return index<this.length?this[index]:null;
};

//~~~~~~~~~~~~~~~~~~~~~~~~
// ElementList extends ItemList
//~~~~~~~~~~~~~~~~~~~~~~~~
function ElementList(){
	ItemList.call(this);
}
ElementList.extends(ItemList);
ElementList.prototype.namedItem=function namedItem(name){
	var index=this.findIndex(function(elem){return elem.name===name;});
	return index===-1?null:this[index];
};


//測试工具函数之获取原型链名单
var getPrototypeNames=(function(){
	function typeOf(value){
		return Object.prototype.toString.call(value).slice(8,-1);
	}
	function isObject(value){
		return typeof value==="object"&&value!==null||typeof value==="function"
	}
	function constructorNameOf(proto){
		return typeof proto.constructor==="function"?proto.constructor.name:typeOf(proto)
	}
	function getPrototypeNames(object){
		var names,proto;
		names=[];
		proto=Object.getPrototypeOf(object);
		while(isObject(proto)){
			names.push(constructorNameOf(proto));
			proto=Object.getPrototypeOf(proto)
		}
		return names;
	}
	return getPrototypeNames;
}());



//运行測试
var list=new ElementList();

console.dir(list);
console.log("list: "+getPrototypeNames(list).join(" > "));

list.push(document.documentElement);
list.push(document.head);
console.assert(list.item(1)===document.head,"The second item of list is document.head");


原文地址:https://www.cnblogs.com/lcchuguo/p/3766136.html