古老的面向對象編程

面向對象編程

clipboard.png

一段完整的建立類的示例javascript

// 如何建立一個類,包含有:靜態屬性方法,公有私有屬性方法?
var Book = (function(){
    // 靜態私有變量 
    var bookNum = 0; 
    
    // 靜態私有方法
    function checkName(name){} 
    
    var _book = function(id, newName, newPrice) { 
        // 安全模式,防止未使用new操做符
        if(this instanceof _book){ 
            // 私有變量 方法 
            var name, price; 
            function checkID(){
            } 
            
            // 公有屬性,方法 
            this.id = id; 
            this.getName = function(){ return name; }; 
            this.getPrice = function(){ return price; }; 
            this.setName = function(name){ name = name; };
            this.setPrice = function(price){ price = price; }; 
            console.log(++bookNum); 
            this.setName(newName); 
            this.setPrice(newPrice);  
        } 
        else{ 
            return new _book(id, name, price); 
        } 
    };
    
    _book.prototype = { 
        // 靜態公有屬性 
        isJSBook: false,
        // 靜態共有方法 
        displayName: function(){ 
            console.log(this.getName());
        } 
    };
    
    return _book;
}());
使用關閉包定義靜態私有變量與方法,全部實例建立過程當中都能訪問到

Paste_Image.png

建立實例時,打印出累加以後的bookNumcss

當替換Book(即_book)的原型以後,以前建立的實例指向的原型並不會改變,以後在以後建立Book實例時運用新的原型

Paste_Image.png

觀察b三、b4的原型html

當在原來的原型上變動以後,經過該原型建立的實例都能應用變動以後的原型

Paste_Image.png

這裏定義重複了,原型上的getPrice方法將會被實例自身擁有的getPrice方法掩蓋住java

繼承編程

  • 方式一:類式繼承: 經過將子類的原型指定爲父類的實例
function SuperClass(){ 
    this.superValue = true;
}
SuperClass.prototype.getSuperValue = function(){ 
    return this.superValue;
};
function SubClass(){
    this.subValue = true;
}
SubClass.prototype = new SuperClass();
SubClass.prototype.getSubValue = function(){ return this.subValue;};

Paste_Image.png

缺點:
一、若是父類中存在引用類型屬性,則會被全部子類共用,一個子類修改以後將會影響到全部子類
二、沒法在實例化時爲父類傳遞初始化參數
  • 方式二: 構造函數繼承: 在子類構造函數中經過call或者apply調用父類的構造函數,實現繼承父類定義的屬性方法
function SuperClass(id){
    this.books = ['js', 'css', 'html'];
    this.id = id;
}
SuperClass.prototype.showBooks = function(){
    console.log(this.books.join());
};
function SubClass(id){
    SuperClass.call(this, id);
}

Paste_Image.png

缺點:
一、子類沒有繼承父類的原型
二、每一個實例化出來的子類對象都會單獨擁有一份父類上定義的屬性方法,沒法複用父類的屬性或者方法
  • 方式三: 組合繼承: 方式一與方式二的組合模式
function SuperClass(name){
    this.name = name;
    this.books = ['js', 'css','html'];
}
SuperClass.prototype.getName = function(){
    console.log(this.name);
};
function SubClass(name, time){
    SuperClass.call(this, name);
    this.time = time;
}
SubClass.prototype = new SuperClass();
SubClass.prototype.getTime = function(){ console.log(this.time);}

Paste_Image.png

缺點:
一、父類構造函數執行了兩遍
二、子類實例化出來的對象原型中重複了一次父類構造函數中的屬性方法
  • 方式四: 原型式繼承: 使用過渡函數做爲構造函數,傳入的對象做爲過渡函數的原型
function inheritObject(o){
    function F(){}
    F.prototype = o;
    return new F();
}
缺點:
跟方式一有相同的缺點
  • 方式五: 寄生式繼承: 在方式四的基礎上進行二次封
function createBook(obj){
    var o = inheritObject(obj);
    o.getName = function(){
        console.log(this.name); 
    };
    
    return o;
}

Paste_Image.png

  • 方式六: 寄生組合式繼承: 寄生式繼承跟夠構造函數繼承的組合
function inheritPrototype(SubClass, SuperClass){
    var p = inheritObject(SuperClass.prototype);
    p.constructor = SubClass;
    SubClass.prototype = p;
}
function SuperClass(name){
    this.name = name;
    this.books = ['js', 'css','html'];
}
SuperClass.prototype.getName = function(){
    console.log(this.name);
};
function SubClass(name, time){
    SuperClass.call(this, name);
    this.time = time;
}
inheritPrototype(SubClass, SuperClass);
SubClass.prototype.getTime = function(){ console.log(this.time);
}

Paste_Image.png

子類添加原型方法只能在現有原型上一個添加

整個過程:先定義子類及父類與父類原型,而後子類原型引用父類的原型對象,而後子類在添加本身的原型方法,最後調用父類構造函數安全

相關文章
相關標籤/搜索