《JavaScript語言精粹》--第5章:繼承
阿新 • • 發佈:2019-01-22
/* 當一個函式物件被建立時,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