老生常談之JavaScript原型鏈繼承

介紹

本文總結了ES3,ES5,ES7和NS(NonStandard)四種原型鏈繼承的實現方法。

前言

ECMAScript 6 class將給開發者帶來JavaScript OOP的規範實現,但這種方式的直接應用和普及至少得等到IE11被淘汰掉,而到那時,說不定我們已轉向邊沿領域了。

隨着Web的快速發展,新的方法可能會隨時取代舊的方法,而我們在lifetime中用過的方法,代表着一代人的記憶,又怎能忘懷?

分享

/**
 * @method ES3Extends
 * @param {Function} sub - subclass constrcutor
 * @param {Function} sup - superclass constrcutor
 * @return {Object} - original prototype of subclass constrcutor
 */
var ES3Extends=(function(){
	// Object.keys polyfill
	// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
	var ObjectGetOwnPropertyNames=Object.getOwnPropertyNames||(function(){
		var hasOwnProperty=Object.prototype.hasOwnProperty,
			hasDontEnumBug=!({toString:null}).propertyIsEnumerable('toString'),
			dontEnums=[
				'toString','toLocaleString','valueOf',
				'hasOwnProperty','isPrototypeOf','propertyIsEnumerable','constructor'
			],
			dontEnumsLength=dontEnums.length;
		function keys(o) {
			if (!(typeof o==='object'&&o!==null||typeof o==='function')){
				throw new TypeError('Object.keys called on non-object');
			}
			var result,i;
			result=[];
			for(i in o) {
				if(hasOwnProperty.call(o,i)){
					result.push(i);
				}
			}
			if(hasDontEnumBug){
				for(i=0; i


另附上BDD測試

describe("4 methods to do prototype-chain extends",function(){
	var List=null;
	beforeEach(function(){
		List=function List(){};
	});
	describe("ES3Extends",function(){
		it("should set prototype of List.prototype to Array.prototype",function(){
			ES3Extends(List,Array);
			expect(List.prototype.push).toBe(Array.prototype.push);
		});
	});
	describe("ES5Extends",function(){
		it("should set prototype of List.prototype to Array.prototype",function(){
			ES5Extends(List,Array);
			expect(Object.getPrototypeOf(List.prototype)).toBe(Array.prototype);
		});
	});
	xdescribe("ES7Extends",function(){
		it("should set prototype of List.prototype to Array.prototype",function(){
			ES7Extends(List,Array);
			expect(Object.getPrototypeOf(List.prototype)).toBe(Array.prototype);
		});
	});
	describe("NSExtends",function(){
		it("should set prototype of List.prototype to Array.prototype",function(){
			NSExtends(List,Array);
			expect(Object.getPrototypeOf(List.prototype)).toBe(Array.prototype);
		});
	});
});

這其中:

  • 較新的JavaScript運行環境能兼容舊的繼承方法,反之則不行。
  • NS方法的效率理論上比其他方法要高,但需進行特性檢測,僅當環境支持所需特性時才能採用此方法。

參考

發佈了45 篇原創文章 · 獲贊 21 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章