1. 程式人生 > >《JavaScript語言精粹》--第5章:繼承

《JavaScript語言精粹》--第5章:繼承

/*
	當一個函式物件被建立時,Function構造器產生的函式物件將會執行類似下面的程式碼:
*/
this.prototype = {
	constructor: this
};

//--------------------------------------------------------------------------------

/*
	偽類建立
		直接使用new + 建構函式建立偽類
*/
var Cat = function(name) {
	this.name = name;
	this.getName = function() {
		return this.name;
	};
	this.speaks = function() {
		return this.sound || "";
	};
	this.run = function() {
		return "Cat is running";
	};
};

var cat = new Cat("Tom");
console.log(cat.getName());
//輸出:
//Tom

//--------------------------------------------------------------------------------

/*
	偽類繼承
		將父類例項付給子類例項的原型進行繼承
*/
var BlackCat = function(name) {
	this.name = name;
	this.sound = "miao";
	this.getName = function() {
		return "BlackCat'name is " + this.name;
	};
};

BlackCat.prototype = new Cat();

Cat.prototype.swim = function() {
	return "cat can swim!"
};

var blackCat = new BlackCat("Black Tom");
console.log(blackCat.speaks());
console.log(blackCat.getName());
console.log(blackCat.run());
console.log(blackCat.swim());
//輸出:
// miao
// BlackCat'name is Black Tom
// Cat is running
// cat can swim! 

//--------------------------------------------------------------------------------

/*
	偽類模式缺點
		偽類沒有私有環境,所有屬性都是公開的,且無法訪問super(父類)的方法
		在使用構造器函式時,若忘記加上new,this將會繫結到全域性物件上,這樣不但沒有擴充新物件,反而破壞了全域性變數環境
*/
console.log(blackCat.name);
console.log(blackCat.sound);
//輸出:
//Black Tom
//miao
/*
	只能訪問到BlackCat類的getName方法,無法訪問到父類的getName方法

*/

//--------------------------------------------------------------------------------


/*
	物件說明符
		構造器要接受一大堆引數時,使用一個物件作為引數將會更加友好
*/

//--------------------------------------------------------------------------------

/*
	函式化模式
		相對於偽類的無法保護隱私的特點,我們更應當使用模組模式,模組模式繼承包括以下內容:
		4個步驟:
			建立一個新物件
			有選擇地定義私有變數和方法
			給這個新物件擴充方法
			返回那個新物件
		spec物件:包含構造器需要構造一個新例項的所有資訊
		my物件:一個為繼承鏈中構造器提供祕密共享的容器
		偽碼:
			var constructor = function(spec, my) {
				var that;
				//定義其他私有變數
				my = my || {};
				//把共享變數和函式放入my中
				that = {};
				//給that新增特權方法
				return that;
			};
*/

//--------------------------------------------------------------------------------

/*
	利用superior方法可以獲得父類方法
*/
// 函式化模式給我們提供了一個處理父類的方法,構造一個superior方法,它取得一個方法名,並返回呼叫那個方法的函式
Object.prototype.superior = function(name) {
	var that = this,
		method = that[name];
	return function() {
		return method.apply(that, arguments);
	};
};

//--------------------------------------------------------------------------------

/*
	函式化模式優點:
		函式化模式有更好的封裝性和資訊隱藏能力,而且可以訪問父類方法
*/

//繼承時,如果需要呼叫父類方法,則可以通過這個Object擴充套件方法進行呼叫
Object.prototype.superior = function(name) {
	var that = this,
		method = that[name];
	return function() {
		return method.apply(that, arguments);
	};
};
//cat基類,有自己的方法getName和speaks
var cat = function(spec) {
	var that = {};
	that.getName = function() {
		return spec.name;
	};
	that.speaks = function() {
		return spec.sound || "";
	};
	return that;
};
//子類,繼承於cat,有自己的方法getName和run,通過superior呼叫了父類方法getName
var blackCat = function(spec) {
	spec.sound = "miao";
	var that = cat(spec), //繼承cat
		superGetName = that.superior("getName"); //通過superior獲得父類同名方法
	//自身的方法
	that.run = function() {
		return "this cat can run";
	};
	//自身的方法
	that.getName = function() {
		return "BlackCat's name is " + spec.name;
	};
	//換名後的父類方法
	that.superGetName = function() {
		return superGetName();
	};
	return that;
};

var myBlackCat = blackCat({
	name: "tom"
});

console.log(myBlackCat.getName());
console.log(myBlackCat.run());
console.log(myBlackCat.speaks());
console.log(myBlackCat.superGetName());
//輸出:
//BlackCat's name is tom
//this cat can run
//miao
//tom