js的繼承
@(js)[繼承, js, 前端]
組合繼承是原性鏈繼承和構造函數繼承的合體,它汲取了二者各自的有點,同時又互相補充了各自的弱點,是一種應用十分廣泛的JavaScript繼承模式。下面分別從原性鏈繼承、構造函數繼承分別開始介紹,最后介紹二者的結合——組合繼承。
一、原型鏈
利用原型讓一個引用類型繼承另一個引用類型的屬性和方法
每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。
實現原性鏈的基本模式:
function SuperType(){ //定義了一個父函數
this.property =true;
}
SuperType.prototype.getSuperValue = function(){ //給父函數的原型鏈上添加一個getSuperValue的函數
returnthis.property;
}
function Subtype(){ //定義一個子函數
this.subproperty =false;
}
SubType.prototype = new SuperType(); //SubType實現了繼承SuperType
SubType.prototype.getSubValue = function(){ //給子函數添加方法
return this.subproperty;
}
var instance = new SubType(); // 實例instance繼承子函數
alert(instance.getSuperValue());
最后的結果:intance指向SubType的原型,而SubType的原型又指向SuperType的原型,SuperType繼承了Object,所有函數的默認原型都是Object的實例
問題:會產生引用類型值的問題
比如,創建了一個子類的實例,如果對子類實例的屬性進行了修改,那么創建其他子類的時候都會收到影響,代碼如下:
function SuperType(){
this.colors =[“red”, “blue”, “green”];
}
function SubType(){
}
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push(“black”);
alert(instance1.colors); //red, blue, green, black
var instance2 = new SubType();
alert(instance2.colors); //red, blue, green, black
以上結果說明會影響其他實例的屬性值
二、借用構造函數
在子類型構造函數的內部調用超類型構造函數
function SuperType(){ // 定義一個父函數
this.colors =[“red”, “blue”, “green”];
}
function SubType{}( // 定義一個子函數
SuperType.call(this); // 繼承了父函數
}
var instance1 = new SubType(); // 實例instance1繼承子函數
instance1.colors.push(“black”);
alert(intance1.colors); //red,blue,green,black
var instance2 = new SubType(); // 實例instance2繼承子函數
alert(instance2.colors); //red,blue,green
使用該方法可以在子類構造函數中向超類型構造函數傳遞參數,如下:
function SuperType(name){ // 定義父函數
this.name = name;
}
function SubType(){ // 定義子函數
SuperType.call(this,“Nicholas”); //傳入參數,利用這個參數初始化父類構造函數中的name
this.age = 29;
}
var instance = new SubType(); // 實例instance繼承子函數
alert(instance.name); //Nicholas
alert(instance.age); //29
問題:不方便復用
三、組合式繼承
使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承
示例代碼:
function SuperType(name){ // 定義父函數
this.name = name: // 定義子函數
this.colors = [“red”, “blue”,“green”];
}
SuperType.prototype.sayName = function(){ //定義了一個方法,該方法在繼承的子類中也可以用
alert(this.name);
}
function SubType(name, age){
SuperType.call(this, name); //繼承SuperType的一部分,this指SubType,
this.age = age; //自己新定義的屬性age也可以進行賦值
}
SubType.prototype = new SuperType(); //利用原型繼承,可以使用父類的方法
SubType.prototype.sayAge = function(){ //定義SubType特有的新方法
alert(this.age);
}
var instance1 = new SubType(“Martin”, 10);
instance1.colors.push(“black”);
alert(instance1.colors); //red,blue,green,black
instance1.sayName(); //Martin
instance1.sayAge(); //10
var instance2 = new SubType(“Greg”, 27);
alert(instance2.colors); //red,blue,green
instance2.sayName(); //Greg
instance2.sayAge(); //27
綜合例子:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.hi = function() {
console.log('Hi, my name is' + this.name) + ",I'm" + this.age + 'years old now.';
};
Person.prototype.LEGS_NUM = 2;
Person.prototype.ARMS_NUM = 2;
Person.prototype.walk = function() {
console.log(this.name + "is walking...");
}
function Student(name, age, className) {
Person.call(this, name, age);
this.className = className;
}
Student.prototype = Objectcreate(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.hi = function() {
console.log('Hi, my name is' + this.name + ", I'm" + this.age + "years old now, and from" + this.className + ".");
}
Student.prototype.learn = function(subject) {
console.log(this.name + 'is learing' + subject + 'at' + this.className + '.');
}
// test
var bosn = new Student('Bosn', 27, 'Class 3,Grade 2');
bosn.hi(); // Hi, my name is Bosn, I'm 27 years old now and from Class3,Grage 2
bosn.LEGS_NUM; // 2
bosn.walk(); // Bosn is walking
bosn.learn('math'); // Bosn is learning math t Class3, Grade 2.