1. 程式人生 > >javaScript面向物件程式設計-繼承(一)

javaScript面向物件程式設計-繼承(一)

類有三部分

  1. 建構函式內的,供例項化物件複製用的
  2. 建構函式外的,直接通過點語法新增的,供類使用,例項化物件訪問不到
  3. 類的原型中的,例項化物件可以通過其原型鏈間接地訪問到,也是供所有例項化物件所共用的。

類式繼承

類的原型物件的作用就是為類的原型新增共有方法,但類不能訪問這些屬性和方法,只有通過原型prototype來訪問。

//類式繼承
//宣告父類
function SuperClass() {
    this.superValue = true;
}
//為父類新增共有方法
SuperClass.prototype.getSuperValue = function () {
    return this.superValue;
};
//宣告子類
function SubClass() {
    this.subValue = false;
}
//繼承父類
SubClass.prototype = new SuperClass();
//為子類新增共有方法
SubClass.prototype.getSubValue = function () {
    return this.subValue;
};
var instance = new SubClass();
console.log(instance.getSuperValue());//true可以這樣使用子類
console.log(instance.getSubValue());//false
console.log(instance instanceof SuperClass);//true
console.log(instance instanceof SubClass);//true
console.log(SubClass instanceof SuperClass);//false

類式繼承的兩個缺點:一、子類通過其原型prototype對父類例項化,繼承了父類。父類的共有屬性要是引用型別,就會在子類中被所有例項共用,一個子類的例項更改子類原型從父類建構函式中繼承的共有屬性就會直接影響其他子類。二、由於子類實現的繼承是靠其原型prototype對父類的例項化實現的,因此在建立父類的時候,無法向父類傳遞引數,在例項化父類的時候也無法對父類建構函式內的屬性進行初始化。

建構函式繼承

//建構函式式繼承
//宣告父類
function SuperClass(id) {
    //引用型別共有屬性
    this.books = ['javascript','html','css'];
    //值型別共有屬性
    this.id = id;
}
//父類宣告原型方法
SuperClass.prototype.showBooks = function () {
    console.log(this.books);
}
//宣告子類
function SubClass(id) {
    //繼承父類
    SuperClass.call(this,id);//將子類的變數在父類中執行一遍
}
//建立第一個子類例項
var instance1 = new SubClass(10);
var instance2 = new SubClass(11);
instance1.books.push('設計模式');
console.log(instance1.books);//[ 'javascript', 'html', 'css', '設計模式' ]
console.log(instance1.id);//10
console.log(instance2.books);//[ 'javascript', 'html', 'css' ]
console.log(instance2.id);//11
instance1.showBooks();//[ 'javascript', 'html', 'css', '設計模式' ]

由於這種型別的繼承沒有涉及原型prototype,所有父類的原型方法自然不會被子類繼承,而如果想要被子類繼承就必須放在建構函式中,這樣建立的每個例項都會單獨擁有一份而不能共用,違背了程式碼複用原則。

組合繼承

前面兩種模式的特點:類式繼承通過子類的原型prototype對父類例項化實現的,建構函式式繼承是通過在子類的建構函式作用環境中執行一次父類的建構函式來實現的。組合繼承同時做到了這兩點。

//組合式繼承
//宣告父類
function SuperClass(name) {
    //值型別共有屬性
    this.name = name;
    //引用型別共有屬性
    this.books = ['html','css','javaScript'];
}
//父類原型共有方法
SuperClass.prototype.getName = function () {
    console.log(this.name);
}
//宣告子類
function SubClass(name,time) {
    //建構函式式繼承父類name屬性
    SuperClass.call(this,name);
    //子類中新增共有屬性
    this.time = time;
}
//類式繼承 子類原型繼承父類
SubClass.prototype = new SuperClass();
//子類原型方法
SubClass.prototype.getTime =function () {
    console.log(this.time);
}
var instance1 = new SubClass('js',2018);
instance1.books.push('設計模式');
console.log(instance1.books);//[ 'html', 'css', 'javaScript', '設計模式' ]
instance1.getName();//js
instance1.getTime();//2018
var instance2 = new SubClass('css',2018);
console.log(instance2.books);//[ 'html', 'css', 'javaScript' ]
instance2.getName();//css
instance2.getTime();//2018

缺點:在使用建構函式繼承時執行了一遍父類的建構函式,而在實現子類原型的類式繼承時又呼叫一遍父類構造器,因此父類構造器呼叫了兩遍。