[js高手之路]從原型鏈開始圖解繼承到組合繼承的產生

來源:互聯網
上載者:User

標籤:輸出   span   錯誤   alt   nbsp   複製   href   person   es2017   

於javascript原型鏈的層層遞進尋找規則,以及原型對象(prototype)的共用特性,實現繼承是非常簡單的事情

一、把父類的執行個體對象賦給子類的原型對象(prototype),可以實現繼承

 1         function Person(){ 2             this.userName = ‘ghostwu‘; 3         } 4         Person.prototype.showUserName = function(){ 5             return this.userName; 6         } 7         function Teacher (){} 8         Teacher.prototype = new Person(); 9 10         var oT = new Teacher(); 11         console.log( oT.userName ); //ghostwu12         console.log( oT.showUserName() ); //ghostwu

通過把父類(Person)的一個執行個體賦給子類Teacher的原型對象,就可以實現繼承,子類的執行個體就可以訪問到父類的屬性和方法

如果你不會畫這個圖,你需要去看下我的這篇文章:[js高手之路]一步步圖解javascript的原型(prototype)對象,原型鏈

第11行,執行oT.userName, 首先去oT對象上尋找,很明顯oT對象上沒有任何屬性,所以就順著oT的隱式原型__proto__的指向尋找到Teacher.prototype,

發現還是沒有userName這個屬性,繼續沿著Teacher.prototype.__proto__向上尋找,找到了new Person() 這個執行個體上面有個userName,值為ghostwu

所以停止尋找,輸出ghostwu.

第12行,執行oT.showUserName前面的過程同上,但是在new Person()這個執行個體上還是沒有尋找到showUserName這個方法,繼續沿著new Person()的

隱式原型__proto__的指向( Person.prototype )尋找,在Person.prototype上找到了showUserName這個方法,停止尋找,輸出ghostwu.

二、把父類的原型對象(prototype)賦給子類的原型對象(prototype),可以繼承到父類的方法,但是繼承不到父類的屬性

 1         function Person(){ 2             this.userName = ‘ghostwu‘; 3         } 4         Person.prototype.showUserName = function(){ 5             return ‘Person::showUserName方法‘; 6         } 7         function Teacher (){} 8         Teacher.prototype = Person.prototype; 9 10         var oT = new Teacher(); 11         console.log( oT.showUserName() ); //ghostwu12         console.log( oT.userName ); //undefined, 沒有繼承到父類的userName

因為Teacher.prototype的隱式原型(__proto__)只指向Person.prototype,所以擷取不到Person執行個體的屬性

三、發生繼承關係後,執行個體與建構函式(類)的關係判斷

還是通過instanceof和isPrototypeOf判斷

 1         function Person(){ 2             this.userName = ‘ghostwu‘; 3         } 4         Person.prototype.showUserName = function(){ 5             return this.userName; 6         } 7         function Teacher (){} 8         Teacher.prototype = new Person(); 9         10         var oT = new Teacher();11         console.log( oT instanceof Teacher ); //true12         console.log( oT instanceof Person ); //true13         console.log( oT instanceof Object ); //true14         console.log( Teacher.prototype.isPrototypeOf( oT ) ); //true15         console.log( Person.prototype.isPrototypeOf( oT ) ); //true16         console.log( Object.prototype.isPrototypeOf( oT ) ); //true

四,父類存在的方法和屬性,子類可以覆蓋(重寫),子類沒有的方法和屬性,可以擴充

 1         function Person() {} 2         Person.prototype.showUserName = function () { 3             console.log(‘Person::showUserName‘); 4         } 5         function Teacher() { } 6         Teacher.prototype = new Person(); 7         Teacher.prototype.showUserName = function(){ 8             console.log(‘Teacher::showUserName‘); 9         }10         Teacher.prototype.showAge = function(){11             console.log( 22 );12         }13         var oT = new Teacher();14         oT.showUserName(); //Teacher::showUserName15         oT.showAge(); //22

五、重寫原型對象之後,其實就是把原型對象的__proto__的指向發生了改變

原型對象prototype的__proto__的指向發生了改變,會把原本的繼承關係覆蓋(切斷)

 1         function Person() {} 2         Person.prototype.showUserName = function () { 3             console.log(‘Person::showUserName‘); 4         } 5         function Teacher() {} 6         Teacher.prototype = new Person(); 7         Teacher.prototype = { 8             showAge : function(){ 9                 console.log( 22 );10             }11         }12         var oT = new Teacher();13         oT.showAge(); //2214         oT.showUserName();

上例,第7行,Teacher.prototype重寫了Teacher的原型對象(prototype),原來第6行的原型對象的隱式原型(__proto__)指向就沒有作用了

所以在第14行,oT.showUserName() 就會發生調用錯誤,因為Teacher的原型對象(prototype)的隱式原型(__proto__)不再指向父類(Person)的執行個體,繼承關係被破壞了.

六、在繼承過程中,小心處理執行個體的屬性上參考型別的資料

 1         function Person(){ 2             this.skills = [ ‘php‘, ‘javascript‘ ]; 3         } 4         function Teacher (){} 5         Teacher.prototype = new Person(); 6  7         var oT1 = new Teacher(); 8         var oT2 = new Teacher(); 9         oT1.skills.push( ‘linux‘ );10         console.log( oT2.skills ); //php, java, linux

oT1的skills添加了一項linux資料,其他的執行個體都能訪問到,因為其他執行個體中共用了skills資料,skills是一個參考型別

七、借用建構函式

為了消除參考型別影響不同的執行個體,可以借用建構函式,把參考型別的資料複製到每個對象上,就不會相互影響了

 1         function Person( uName ){ 2             this.skills = [ ‘php‘, ‘javascript‘ ]; 3             this.userName = uName; 4         } 5         Person.prototype.showUserName = function(){ 6             return this.userName; 7         } 8         function Teacher ( uName ){ 9             Person.call( this, uName );10         }11         var oT1 = new Teacher();12         oT1.skills.push( ‘linux‘ );13         var oT2 = new Teacher();14         console.log( oT2.skills ); //php,javascript15         console.log( oT2.showUserName() );

 雖然oT1.skills添加了一項Linux,但是不會影響oT2.skills的資料,通過子類建構函式中call的方式,去借用父類的建構函式,把父類的屬性複製過來,而且還能

傳遞參數,如第8行,但是第15行,方法調用錯誤,因為在構造中只複製了屬性,不會複製到父類原型對象上的方法

八、組合繼承(原型對象+借用建構函式)

經過以上的分析, 單一的原型繼承的缺點有:

1、不能傳遞參數,如,

 Teacher.prototype = new Person();

有些人說,小括弧後面可以跟參數啊,沒錯,但是只要跟了參數,子類所有的執行個體屬性,都是跟這個一樣,說白了,還是傳遞不了參數

2、把參考型別放在原型對象上,會在不同執行個體上產生相互影響

單一的借用建構函式的缺點:

1、不能複製到父類的方法

剛好原型對象方式的缺點,借用建構函式可以彌補,借用建構函式的缺點,原型對象方式可以彌補,於是,就產生了一種組合繼承方法:

 1         function Person( uName ){ 2             this.skills = [ ‘php‘, ‘javascript‘ ]; 3             this.userName = uName; 4         } 5         Person.prototype.showUserName = function(){ 6             return this.userName; 7         } 8         function Teacher ( uName ){ 9             Person.call( this, uName );10         }11         Teacher.prototype = new Person();12 13         var oT1 = new Teacher( ‘ghostwu‘ );14         oT1.skills.push( ‘linux‘ );15         var oT2 = new Teacher( ‘ghostwu‘ );16         console.log( oT2.skills ); //php,javascript17         console.log( oT2.showUserName() ); //ghostwu

子類執行個體oT2的skills不會受到oT1的影響,子類的執行個體也能調用到父類的方法.

[js高手之路]從原型鏈開始圖解繼承到組合繼承的產生

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.