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