关于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");