繼承
本文是在讀了JavaScript設計模式的繼承部分做的總結
類式繼承
function Father(firstName){
this.firstName = firstName;
this.family = ["father", "mother", "son"];
}
Father.prototype.showFirstName = function(){
return this.firstName;
}
function Child(sex){
this.sex = sex;
}
Child.prototype = new Father("ccc");
var me = new Child("male");
console.log(me.showFirstName());
類式繼承最重要的一步是將父類的實例賦值給子類的prototype對象
實例化的父類包含了父類的共有屬性和方法,然後這個實例化的對象的 _ proto_ 屬性又指向了父類的prototype對象,所以這個實例對象能訪問父類原型上的屬性和方法
當把這個實例化的對象賦值給子類的prototype屬性時,子類的原型也就能訪問到父類的原型上的屬性和方法了
用子類實例化的對象能訪問到子類的原型,所以進而能訪問到父類的原型
me.__proto__ === Child.prototype;
Child.prototype.__proto__ === Father.prototype;
me.__proto__.__proto__ === Father.prototype;
類式繼承有下面兩個問題:
- 如果父類裏的公有屬性有引用類型的,實例化子類後,這些屬性的修改會相互影響
- 實例化子類的時候無法向父類傳遞參數並初始化父類裏的公有屬性
var son = new Child("male"),
daugter = new Child("famale");
son.family.push("daugter");
console.log(son.family);
console.log(daugter.family); // ["father", "mother", "son", "daugter"]
//daugter實例對象的family屬性也被修改了
構造函數繼承
function Father(firstName, family){
this.firstName = firstName;
this.family = family;
this.showFirstName = function(){
return this.firstName;
}
}
function Child(sex, firstName, family){
this.sex = sex;
Father.call(this, firstName, family);
}
var son = new Child("male", "c", ["father", "mother", "son"]);
console.log(son);
構造函數繼承的重點在於,Father.call(this, “”, “”),用子類的this對象去調用父類的構造函數,這樣就能在子類的實例化的對象上覆制綁定父類的公有屬性和方法,互不影響,但是對於本應共享的方法也都複製了一份,不能共用
組合繼承
function Father(firstName){
this.firstName = firstName;
this.family = ["father", "mother"];
}
Father.prototype.showFirstName = function(){
return this.firstName;
}
function Child(sex, firstName){
this.sex = sex;
Father.call(this, firstName);
}
Child.prototype = new Father();
var son = new Child("male", "c");
console.log(son.showFirstName()); // "c"
組合繼承的過程中,父類的構造函數被執行了兩遍,會導致子類實例化的對象的原型鏈上有重名的屬性,當訪問時,子類的屬性會覆蓋原型鏈上重名的屬性
寄生式繼承
function inherit(father){
function F(){}
F.prototype = father;
return new F();
//這麼做的目的就是得到一個乾淨的實例,沒有父類裏的公有屬性,只保留了父類原型上的屬性和方法
}
var family = {
count: 3,
person: ["father", "mother", "son"]
}
function createFamily(obj){
var o = inherit(obj);
o.getCount = function(){
return this.count;
}
return o;
}
var test = createFamily(family);
console.log(test);
寄生組合式繼承
function inherit(father){
function F(){}
F.prototype = father;
return new F();
}
function inheritPrototype(child, father){
var p = inherit(father.prototype);
p.constructor = child;
//這裏的p,感覺更像是個過度,一個乾淨的繼承了父類原型的對象,然後其constructor屬性被更正到了子類上,整個過程變得更加清晰,層次更清楚
child.prototype = p;
}
function Father(firstName){
this.firstName = firstName;
this.family = ["father", "mother"];
}
Father.prototype.showFirstName = function(){
return this.firstName;
}
function Child(sex, firstName){
this.sex = sex;
Father.call(this, firstName);
}
inheritPrototype(Child, Father);
Child.prototype.showSex = function(){
return this.sex;
}
var son = new Child("male", "c");
console.log(son);
上面關於寄生組合繼承實現方式,無意中發現這種方式也許更好
function Father(firstName){
this.firstName = firstName;
this.family = ["father", "mother"];
}
Father.prototype.showFirstName = function(){
return this.firstName;
}
function Child(sex, firstName){
this.sex = sex;
Father.call(this, firstName);
}
Object.setPrototypeOf(Child.prototype, Father.prototype);
Child.prototype.showSex = function(){
return this.sex;
}
var son = new Child("male", "c");
console.log(son);