1. 程式人生 > >[js高手之路]從原型鏈開始圖解繼承到組合繼承的產生

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

於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 ); //ghostwu 12 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() ); //ghostwu
12         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 ); //true
12         console.log( oT instanceof Person ); //true
13         console.log( oT instanceof Object ); //true
14         console.log( Teacher.prototype.isPrototypeOf( oT ) ); //true
15         console.log( Person.prototype.isPrototypeOf( oT ) ); //true
16         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::showUserName
15         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(); //22
14         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,javascript
15         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,javascript
17         console.log( oT2.showUserName() ); //ghostwu

子類例項oT2的skills不會受到oT1的影響,子類的例項也能呼叫到父類的方法.

相關推薦

[js高手]原型開始圖解繼承組合繼承產生

於javascript原型鏈的層層遞進查詢規則,以及原型物件(prototype)的共享特性,實現繼承是非常簡單的事情 一、把父類的例項物件賦給子類的原型物件(prototype),可以實現繼承 1 function Person(){ 2

[js高手]開始打造一個javascript開源框架gdom與外掛開發免費視訊教程連載中

具體課程目錄: 1,課程安排【視訊已上傳】 2,gdom框架使用方法【視訊已上傳】 3,變數提升【視訊已上傳】 4,變數提升之同名變數,函式宣告,表示式的提升規則【視訊已上傳】 5,this關鍵字專題詳解【視訊已上傳】 6,物件在記憶體中的表現形式【視訊已上傳】 7,圖解原型物件與隱式原

[js高手]使用原型對象(prototype)需要註意的地方

spa ray show 特性 之路 對象 重復 new i++ 我們先來一個簡單的構造函數+原型對象的小程序 1 function CreateObj( uName, uAge ) { 2 this.userName = uN

[js高手]一步步圖解javascript的原型(prototype)對象,原型

create 原型對象 str 對象賦值 div blank type屬性 查找 __proto__ 我們接著上文繼續,我們通過原型方式,解決了多個實例的方法共享問題,接下來,我們就來搞清楚原型(prototype),原型鏈的來龍去脈. 1 functio

[js高手]原型對象(prototype)與原型相關屬性與方法詳解

隱式 之前 username tar uname create pro getproto .get 一,instanceof: instanceof檢測左側的__proto__原型鏈上,是否存在右側的prototype原型. 我在之前的兩篇文章 [js高手之路]構造函數的基

[js高手]var, let, const詳解

兩種 控制 ghost 花括號 pre 內部 span lec 同名 1 function show( flag ){ 2 console.log( a ); 3 if( flag ){ 4

[js高手] dom常用節點屬性兼容性詳解與應用

asc 子元素 種類型 process 變色 tex 如果 結構 節點和 一、每個DOM節點都有一個nodeType屬性,表示節點類型, NodeType一共有12種類型,我們可以通過遍歷內置的Node構造函數獲取 1 window.onload =

[js高手]設計模式系列課程-單例模式實現模態框

ges 點擊 eat abs select nbsp str osi 控制 什麽是單例呢? 單,就是一個的意思。例:就是實例化出來的對象,那合在一起就是保證一個構造函數只能new出一個實例,為什麽要學習單例模式呢?或者說單例模式有哪些常見的應用場景.它的使用還是很廣泛,比如

[js高手] 我的開源javascript框架gdom - 選擇器用法

htm query bsp https title 是我 pad logs ext gdom框架是我開發的一款dom和字符串處理框架,目前版本是1.0.0. 使用方法跟jquery是差不多的, 會用jquery就會用gdom,目前 1.0.0版本的選擇器完全支持CSS3選擇

[js高手]設計模式系列課程-委托模式實戰微博發布功能

i++ 發布 動態 use shee 內容 標題 cnblogs 文件 在實際開發中,經常需要為Dom元素綁定事件,如果頁面上有4個li元素,點擊對應的li,彈出對應的li內容,怎麽做呢?是不是很簡單? 大多數人的做法都是:獲取元素,綁定事件 1 <ul&

[js高手]設計模式系列課程-發布者,訂閱者重構購物車

購物車 代碼重構 發布者訂閱者模式,是一種很常見的模式,比如:一、買賣房子生活中的買房,賣房,中介就構成了一個發布訂閱者模式,買房的人,一般需要的是房源,價格,使用面積等信息,他充當了訂閱者的角色中介拿到賣主的房源信息,根據手頭上掌握的客戶聯系信息(買房的人的手機號),通知買房的人,他充當了發布者的角

[js高手]面向對象+設計模式+繼承一步步改造簡單的四則運算

繼承 設計模式 到目前為止,我已經寫完了面向對象完整的一個系列知識,前面基本屬於理論,原理的理解,接下來,我們就用學到的知識來實戰下吧.看看理解原理和理論是否重要?例子從簡單到復雜一、單體(字面量)封裝加減乘除var Oper = { add : function( n1, n

[js高手]原型式繼承與寄生式繼承

原型式繼承 寄生式繼承 一、原型式繼承本質其實就是個淺拷貝,以一個對象為模板復制出新的對象function object( o ){ var G = function(){}; G.prototype = o; return ne

[js高手]node js系列課程-創建簡易web服務器與文件讀寫

server 分享 回調 能夠 logs 瀏覽器中 文件 讀取 對象 web服務器至少有以下幾個特點: 1、24小時不停止的工作,也就是說這個進程要常駐在內存中 2、24小時在某一端口監聽,如: http://localhost:8080, www服務器默認端口80 3、要

[js高手]javascript騰訊面試題學習封裝一個簡易的異步隊列

騰訊 selector host .proto 算法 obj 代碼 ner 試題 這道js的面試題,是這樣的,頁面上有一個按鈕,一個ul,點擊按鈕的時候,每隔1秒鐘向ul的後面追加一個li, 一共追加10個,li的內容從0開始技術( 0, 1, 2, ....9 ),首先我

[js高手]深入淺出webpack系列1-安裝與基本打包用法和命令參數

查看 2-2 gre colors 令行 一起 切換 json round webpack,我想大家應該都知道或者聽過,Webpack是前端一個工具,可以讓各個模塊進行加載,預處理,再進行打包。現代的前端開發很多環境都依賴webpack構建,比如vue官方就推薦使用webp

[js高手]深入淺出webpack教程系列2-配置文件webpack.config.js詳解

基本用法 tle webpack 函數 ges 配置 ref 高手之路 pack 接著上文,重新在webpack文件夾下面新建一個項目文件夾demo2,然後用npm init --yes初始化項目的package.json配置文件,然後安裝webpack( npm inst

[js高手]深入淺出webpack教程系列3-配置文件webpack.config.js詳解(下)

json 學習 所在 npm chunk target get lan cnblogs 本文繼續接著上文,繼續寫下webpack.config.js的其他配置用法. 一、把兩個文件打包成一個,entry怎麽配置? 在上文中的webpack.dev.config.js中,用數

[js高手]深入淺出webpack教程系列4-插件使用html-webpack-plugin配置(上)

技術 輸出 js函數 動態生成 git tro mon ebp 執行 還記得我們上文中的index.html文件嗎? 那裏面的script標簽還是寫死的index.bundle.js文件,那麽怎麽把他們變成動態的index.html文件,這個動態生成的index.html文

[js高手]深入淺出webpack教程系列5-插件使用html-webpack-plugin配置(中)

logs 定義數據 ash con ack move lan ref min 上文我們講到了options的配置和獲取數據的方式,本文,我們繼續深入options的配置 一、html-webpack-plugin插件中的options除了自己定義了一些基本配置外,我們是可以