js面向对象和继承的碎碎念
2019獨角獸企業重金招聘Python工程師標準>>>
一、prototype屬性的特點:
1、定義在prototype中的方法是"實例方法",必須是new出來的實例,才能調用prototype中的方法,相同的方法可以被不同的實例調用,互不干擾:
function?Human?(name)?{this.name?=?name; } Human.prototype?=?{sayHi:function?()?{console.log('Hi!?I\'m?'+this.name+'.');} }var?tom?=?new?Human('Tom'); tom.sayHi();//??Hi!?I'm?Tom. var?perter?=?new?Human('Perter'); perter.sayHi();//?Hi!?I'm?Perter.可以做個小調整,將打招呼的的方法sayHi()移到構造函數中,一實例化就執行,不必單獨調用:
function?Human?(name)?{this.name?=?name;this.sayHi() } Human.prototype?=?{sayHi:function?()?{console.log('Hi!?I\'m?'+this.name+'.');} }var?tom?=?new?Human('Tom');//??Hi!?I'm?Tom. var?perter?=?new?Human('Perter');//?Hi!?I'm?Perter.自問:但是,這樣跟在window全局作用域寫個sayHi方法,傳不同值調用有何區別?:
function?sayHi?(name)?{console.log("Hi!?I'm?"+name+'.'); } sayHi('Tom');//??Hi!?I'm?Tom. sayHi('Perter');//?Hi!?I'm?Perter.自答:全局的function對象適合封裝簡單的小塊邏輯,如果是較為復雜的邏輯,都寫在一個function對象中會使邏輯更趨復雜,難以維護,一般會拆分成多個function,以便于管理和維護:
function?Human?(name)?{this.name?=?name;this.sayHi() } Human.prototype?=?{sayHi:function?()?{console.log('Hi!?I\'m?'+this.name+'.');},work:function?()?{console.log("For?live,I?must?work.");},eat:function?()?{console.log("For?live,I?must?eat.");}sex:function?()?{console.log("Sex?is?an?instinct");} }上例的Human類比開始多定義了3個方法,prototype實現的是,對已經拆分的邏輯模塊(sayHi,work,eat,sex),再封裝后的復用,這是一個簡單的function對象難以做到的。
2、其他屬性定義的方法都是"靜態方法",只能在統一不變的"類"的層級調用。
??3、??獨立的json對象也是封裝邏輯的很好容器,但因為是引用類型,在相同的文檔上下文中,復用會出現后者參數覆蓋前者的情況。
二、使用prototype的注意事項:
1、如果使用xx.prototype={}的方式封裝邏輯,會影響"constructor"值,所以使用后注意重置"constructor"為當前的類。方便以后判斷一個實例的構造類是誰。
function?Human?(name)?{this.name?=?name; } var?a?=?new?Human('Peter'); console.log(a.constructor);上面代碼的輸出結果是:
我們得到了實例a的構造類是Human!
但是使用xx.prototype={}的方式封裝邏輯后:
function?Human?(name)?{this.name?=?name; } Human.prototype?=?{sayHi:function?()?{console.log("Hi!?I'm?"+this.name+'.');} } var?a?=?new?Human('Peter'); console.log(a.constructor);輸出結果是:
我們已經不再知道實例a的構造類是誰?所以,應該重置"constructor"為當前的類:
function?Human?(name)?{this.name?=?name; } Human.prototype?=?{sayHi:function?()?{console.log("Hi!?I'm?"+this.name+'.');} } Human.prototype.constructor?=?Human; var?a?=?new?Human('Peter'); console.log(a.constructor);輸出結果又是:
2、在構建繼承父類的子類時,子類會調用父類的構造函數,生成實例,再賦值給子類的prototype。也就是子類還沒調用,子類繼承自父類的構造方法已經執行了。
//?定義"人"類 function?Human?()?{alert("hello?world!"); } Human.prototype?=?{sayHi:function?()?{console.log("hello?world!");} } Human.prototype.constructor?=?Human;//?定義"女人"類 function?Woman?(name)?{} //?"女人"類繼承"人"類 Woman.prototype?=?new?Human(); //?定義"女人"類的特有方法 Woman.prototype.bear?=?function?()?{console.log("I?can?bear?baies."); } Woman.prototype.constructor?=?Woman;上述代碼只是定義了一個Human類,然后Woman子類繼承Human父類,還沒有實例化,就執行了
alert("hello?world!");不僅不合理,當父類構造函數含有破壞性代碼,或者要依賴特定狀態時,還會引發其他錯誤。
所以,通常我們需要單獨封裝一個實現繼承的方法,而不是僅僅把子類的prototype賦值為父類的實例。
三、繼承方法的封裝步驟:
3.1.構造一個新類,該類具有一個空的構造函數,將該類的prototype賦值為父類的prototype,然后將該類的實例賦值給子類的prototype:
function?inheritance(){}; inheritance.prototype?=?superClass.prototype; subClass.prototype?=?new?inheritance();構造函數為空了,子類再來繼承時,也就不會出現還沒實例化,代碼已經開始執行的情況了。
3.2.重置恢復子類的constructor:
subClass.prototype.constructor?=?subClass;便于對實例追根溯源。
3.3.子類自定義屬性(baseConstructor)保存對父類的構造函數的引用:
subClass.baseConstructor?=?superClass;構造函數只是在過度的“inheritance”類置空了,它的引用仍然會通過子類的自定義屬性(baseConstructor)保留,方便在需要的時候調用。
3.4.如果父類自定義屬性(__super__)包含對祖父類的引用,那么這個屬性要賦值給父類prototype下的同名屬性:
if(superClass.__super__){superClass.prototype.__super__?=?superClass.__super__; }只要保存在prototype屬性中的方法才能被后代繼承,這樣做方便子類對祖先類的方法的重寫。
3.5.子類自定義屬性(__super__)保存對父類的prototype的引用:
方便子類對父類的方法的重寫。
完整的代碼:
//?實現繼承的方法 function?extend?(subClass,superClass)?{//?創建一個新的類,該類具有一個空的構造函數,并具有父類的成員function?inheritance(){};inheritance.prototype?=?superClass.prototype;//?將子類的prototype屬性設置為不帶構造函數的父類新實例subClass.prototype?=?new?inheritance();subClass.prototype.constructor?=?subClass;//?重置恢復constructor屬性subClass.baseConstructor?=?superClass;//?用自定義屬性保存父級的構造函數//?允許多重繼承if(superClass.__super__){superClass.prototype.__super__?=?superClass.__super__;}subClass.__super__?=?superClass.prototype;//?保持對父類原型的引用,方便子類重寫 },
轉載于:https://my.oschina.net/710409599/blog/618884
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的js面向对象和继承的碎碎念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: golang(5):编写WebSocke
- 下一篇: 收集Cocos2d提供的字体