天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

Javascript 繼承機制的實現

選定基類后,就可以創建它的子類了。是否使用基類完全由你決定。有時,你可能想創建一個不能直接使用的基類,它只是用于給子類提供通用的函數。在這種情況下,基類被看作抽象類。

盡管ECMAScript并沒有像其他語言那樣嚴格地定義抽象類,但有時它的確會創建一些不允許使用的類。通常,我們稱這種類為抽象類。

創建的子類將繼承超類的所有屬性和方法,包括構造函數及方法的實現。記住,所有屬性和方法都是公用的,因此子類可直接訪問這些方法。子類還可添加超類中沒有的新屬性和方法,也可以覆蓋超類中的屬性和方法。

4.2.1 繼承的方式

和其他功能一樣,ECMAScript中實現繼承的方式不止一種。這是因為JavaScript中的繼承機制并不是明確規定的,而是通過模仿實現的。這意味著所有的繼承細節并非由解釋程序處理。作為開發者,你有權決定最適用的繼承方式。

1. 對象冒充

構想原始的ECMAScript時,根本沒打算設計對象冒充(object masquerading)。它是在開發者開始理解函數的工作方式,尤其是如何在函數環境中使用this關鍵字后才發展出來的。

其原理如下:構造函數使用this關鍵字給所有屬性和方法賦值(即采用類聲明的構造函數方式)。因為構造函數只是一個函數,所以可使ClassA的構造函數成為ClassB的方法,然后調用它。ClassB就會收到ClassA的構造函數中定義的屬性和方法。例如,用下面的方式定義ClassA和ClassB:

還記得嗎?關鍵字this引用的是構造函數當前創建的對象。不過在這個方法中,this指向的是所屬的對象。這個原理是把ClassA作為常規函數來建立繼承機制,而不是作為構造函數。如下使用構造函數ClassB可以實現繼承機制:

在這段代碼中,為ClassA賦予了方法newMethod(記住,函數名只是指向它的指針)。然后調用該方法,傳遞給它的是ClassB構造函數的參數sColor。最后一行代碼刪除了對ClassA的引用,這樣以后就不能再調用它。

所有的新屬性和新方法都必須在刪除了新方法的代碼行后定義。否則,可能會覆蓋超類的相關屬性和方法:

為證明前面的代碼有效,可以運行下面的例子:

有趣的是,對象冒充可以支持多重繼承。也就是說,一個類可以繼承多個超類。用UML表示的多繼承機制如圖4-2所示。

圖  4-2

例如,如果存在兩個類ClassX和ClassY,ClassZ想繼承這兩個類,可以使用下面的代碼:

這里存在一個弊端,如果ClassX和ClassY具有同名的屬性或方法,ClassY具有高優先級,因為繼承的是最后的類。除這點小問題之外,用對象冒充實現多繼承機制輕而易舉。

由于這種繼承方法的流行,ECMAScript的第三版為Function對象加入了兩個新方法,即call()和apply()。

2. call()方法

call()方法是與經典的對象冒充方法最相似的方法。它的第一個參數用作this的對象。其他參數都直接傳遞給函數自身。例如:

在這個例子中,函數sayColor()在對象外定義,即使它不屬于任何對象,也可以引用關鍵字this。對象obj的color屬性等于"red"。調用call()方法時,第一個參數是obj,說明應該賦予sayColor()函數中的this關鍵字值是obj。第二個和第三個參數是字符串。它們與sayColor()函數中的參數prefix和suffix匹配,最后生成的消息"The color is red, a very nice color indeed"將被顯示出來。

要與繼承機制的對象冒充方法一起使用該方法,只需將前三行的賦值、調用和刪除代碼替換即可:

這里,想讓ClassA中的關鍵字this等于新創建的ClassB對象,因此this是第一個參數。第二個參數sColor對兩個類來說都是唯一的參數。

3. apply()方法

apply()方法有兩個參數,用作this的對象和要傳遞給函數的參數的數組。例如:

這個例子與前面的例子相同,只是現在調用的是apply()方法。調用apply()方法時,第一個參數仍是obj,說明應該賦予sayColor()中的this關鍵字值是obj。第二個參數是由兩個字符串構成的數組,與sayColor()的參數prefix和suffix匹配。生成的消息仍是"The color is red, a very nice color indeed",將被顯示出來。

該方法也用于替換前三行的賦值、調用和刪除新方法的代碼:

同樣的,第一個參數仍是this。第二個參數是只有一個值color的數組。可以把ClassB的整個arguments對象作為第二個參數傳遞給apply()方法:

當然,只有超類中的參數順序與子類中的參數順序完全一致時才可以傳遞參數對象。如果不是,就必須創建一個單獨的數組,按照正確的順序放置參數。此外,還可使用call()方法。

4. 原型鏈

繼承這種形式在ECMAScript中原本是用于原型鏈的。上一章介紹了定義類的原型方式。原型鏈擴展了這種方式,以一種有趣的方式實現繼承機制。

在上一章中學過,prototype對象是個模板,要實例化的對象都以這個模板為基礎。總而言之,prototype對象的任何屬性和方法都被傳遞給那個類的所有實例。原型鏈利用這種功能來實現繼承機制。

如果用原型方式重定義前面例子中的類,它們將變為下列形式:

原型鏈的神奇之處在于突出顯示的代碼行。這里,把ClassB的prototype屬性設置成ClassA的實例。這很有意義,因為想要ClassA的所有屬性和方法,但又不想逐個將它們賦予ClassB的prototype屬性。還有比把ClassA的實例賦予prototype屬性更好的方法嗎?

注意,調用ClassA的構造函數時,沒有給它傳遞參數。這在原型鏈中是標準做法。要確保構造函數沒有任何參數。

與對象冒充相似,子類的所有屬性和方法都必須出現在prototype屬性被賦值后,因為在它之前賦值的所有方法都會被刪除。為什么?因為prototype屬性被替換成了新對象,添加了新方法的原始對象將被銷毀。所以,為ClassB類添加name屬性和sayName()方法的代碼如下:

可通過運行下面的例子測試這段代碼:

此外,在原型鏈中,instanceof運算符的運行方式也很獨特。對ClassB的所有實例,instanceof為ClassA和ClassB都返回true。例如:

在ECMAScript的弱類型世界中,這是極其有用的工具,不過使用對象冒充時不能使用它。

原型鏈的弊端是不支持多重繼承。記住,原型鏈會用另一類型的對象重寫類的prototype屬性。

5. 混合方式

這種繼承方式使用構造函數定義類,并未使用任何原型。對象冒充的主要問題是必須使用構造函數方式(如上一章中學到的),這不是最好的選擇。不過如果使用原型鏈,就無法使用帶參構造函數了。開發者該如何選擇呢?答案很簡單,兩者都用。

在前一章,你學過創建類的最好方式是用構造函數方式定義屬性,用原型方式定義方法。這種方式同樣適用于繼承機制,用對象冒充繼承構造函數的屬性,用原型鏈繼承prototype對象的方法。用這兩種方式重寫前面的例子,代碼如下:

在此例子中,繼承機制由兩行突出顯示的代碼實現。在第一行突出顯示的代碼中,在ClassB構造函數中,用對象冒充繼承ClassA類的sColor屬性。在第二行突出顯示的代碼中,用原型鏈繼承ClassA類的方法。由于這種混合方式使用了原型鏈,所以instanceof運算符仍能正確運行。

下面的例子測試了這段代碼:

JavaScript技術Javascript 繼承機制的實現,轉載需保留來源!

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

主站蜘蛛池模板: 国产-第1页-浮力影院 | 亚洲 中文 自拍 无码 | 九九热视频在线观看 | 国产午夜精品福利久久 | 深爱激情站 | 久久机热视频 这里只有精品首页 | 男女交性视频无遮挡全过程 | 久久WWW免费人成一看片 | 动漫美女禁区 | 色愁愁久久久 | 国产超碰AV人人做人人爽 | 波多野结衣的AV一区二区三区 | 亚洲国产女人aaa毛片在线 | 芒果影院网站在线观看 | 欧美巨大巨粗黑人性AAAAAA | 诱咪youmiss| 国产99久久亚洲综合精品西瓜tv | 粗壮挺进邻居人妻无码 | 亚洲欧美色综合影院 | 精品日产1区2卡三卡麻豆 | 成人中文字幕在线观看 | 亚洲野狼综合网站 | 又大又硬又爽免费视频 | 菠萝菠萝蜜在线观看视频 | 免费的av不用播放器的 | 久久99re2热在线播放7 | 国精一区二区AV在线观看网站 | 国产激情精品久久久久久碰 | 亲爱的妈妈6韩国电影免费观看 | 日本无码免费久久久精品 | 亚洲第一区欧美日韩精品 | 99国产精品成人免费视频 | 亚洲AV人无码综合在线观看蜜桃 | 日韩精品免费在线观看 | CHINA篮球体育飞机2022网站 | 老师系列高H文 | 亚洲AV久久无码精品国产网站 | 真人做受120分钟免费看 | 一本二卡三卡四卡乱码麻豆 | 99久久亚洲精品日本无码 | 国产精品第一综合首页 |