成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

說說 JavaScript 的 Mixin 模式

開發(fā) 前端
在 JavaScript 中,我們只能繼承單個(gè)對(duì)象。每個(gè)對(duì)象只能有一個(gè) [[Prototype]]。并且每個(gè)類只可以擴(kuò)展另外一個(gè)類。但是有些時(shí)候這種設(shè)定(譯注:?jiǎn)卫^承)會(huì)讓人感到受限制。例如,我有一個(gè) StreetSweeper 類和一個(gè) Bicycle 類,現(xiàn)在想要一個(gè)它們的 mixin:StreetSweepingBicycle 類。

[[359214]]

 在 JavaScript 中,我們只能繼承單個(gè)對(duì)象。每個(gè)對(duì)象只能有一個(gè) [[Prototype]]。并且每個(gè)類只可以擴(kuò)展另外一個(gè)類。

但是有些時(shí)候這種設(shè)定(譯注:?jiǎn)卫^承)會(huì)讓人感到受限制。例如,我有一個(gè) StreetSweeper類和一個(gè) Bicycle 類,現(xiàn)在想要一個(gè)它們的 mixin:StreetSweepingBicycle 類。

或者,我們有一個(gè) User 類和一個(gè) EventEmitter 類來實(shí)現(xiàn)事件生成(event generation),并且我們想將 EventEmitter 的功能添加到 User 中,以便我們的用戶可以觸發(fā)事件(emit event)。

有一個(gè)概念可以幫助我們,叫做 “mixins”。

根據(jù)維基百科的定義,mixin 是一個(gè)包含可被其他類使用而無需繼承的方法的類。

換句話說,mixin 提供了實(shí)現(xiàn)特定行為的方法,但是我們不單獨(dú)使用它,而是使用它來將這些行為添加到其他類中。

一、一個(gè) Mixin 實(shí)例

在 JavaScript 中構(gòu)造一個(gè) mixin 最簡(jiǎn)單的方式就是構(gòu)造一個(gè)擁有實(shí)用方法的對(duì)象,以便我們可以輕松地將這些實(shí)用的方法合并到任何類的原型中。

例如,這個(gè)名為 sayHiMixin 的 mixin 用于給 User 添加一些“語言功能”:

  1. // mixin 
  2. let sayHiMixin = { 
  3.   sayHi() { 
  4.     alert(`Hello ${this.name}`); 
  5.   }, 
  6.   sayBye() { 
  7.     alert(`Bye ${this.name}`); 
  8.   } 
  9. }; 
  10.  
  11. // 用法: 
  12. class User { 
  13.   constructor(name) { 
  14.     this.name = name
  15.   } 
  16.  
  17. // 拷貝方法 
  18. Object.assign(User.prototype, sayHiMixin); 
  19.  
  20. // 現(xiàn)在 User 可以打招呼了 
  21. new User("Dude").sayHi(); // Hello Dude! 

 這里沒有繼承,只有一個(gè)簡(jiǎn)單的方法拷貝。所以 User 可以從另一個(gè)類繼承,還可以包括 mixin 來 "mix-in“ 其它方法,就像這樣 :

  1. class User extends Person { 
  2.   // ... 
  3.  
  4. Object.assign(User.prototype, sayHiMixin); 

 Mixin 可以在自己內(nèi)部使用繼承。

例如,這里的 sayHiMixin 繼承自 sayMixin:

  1. let sayMixin = { 
  2.   say(phrase) { 
  3.     alert(phrase); 
  4.   } 
  5. }; 
  6.  
  7. let sayHiMixin = { 
  8.   __proto__: sayMixin, // (或者,我們可以在這兒使用 Object.create 來設(shè)置原型) 
  9.  
  10.   sayHi() { 
  11.     // 調(diào)用父類方法 
  12.     super.say(`Hello ${this.name}`); // (*) 
  13.   }, 
  14.   sayBye() { 
  15.     super.say(`Bye ${this.name}`); // (*) 
  16.   } 
  17. }; 
  18.  
  19. class User { 
  20.   constructor(name) { 
  21.     this.name = name
  22.   } 
  23.  
  24. // 拷貝方法 
  25. Object.assign(User.prototype, sayHiMixin); 
  26.  
  27. // 現(xiàn)在 User 可以打招呼了 
  28. new User("Dude").sayHi(); // Hello Dude! 

 請(qǐng)注意,在 sayHiMixin 內(nèi)部對(duì)父類方法 super.say() 的調(diào)用(在標(biāo)有 (*) 的行)會(huì)在 mixin 的原型中查找方法,而不是在 class 中查找。

這是示意圖(請(qǐng)參見圖中右側(cè)部分):


這是因?yàn)榉椒?sayHi 和 sayBye 最初是在 sayHiMixin 中創(chuàng)建的。因此,即使復(fù)制了它們,但是它們的 [[HomeObject]] 內(nèi)部屬性仍引用的是 sayHiMixin,如上圖所示。

當(dāng) super 在 [[HomeObject]].[[Prototype]] 中尋找父方法時(shí),意味著它搜索的是 sayHiMixin.[[Prototype]],而不是 User.[[Prototype]]。

二、EventMixin

現(xiàn)在讓我們?yōu)閷?shí)際運(yùn)用構(gòu)造一個(gè) mixin。

例如,許多瀏覽器對(duì)象的一個(gè)重要功能是它們可以生成事件。事件是向任何有需要的人“廣播信息”的好方法。因此,讓我們構(gòu)造一個(gè) mixin,使我們能夠輕松地將與事件相關(guān)的函數(shù)添加到任意 class/object 中。

  • Mixin 將提供 .trigger(name, [...data]) 方法,以在發(fā)生重要的事情時(shí)“生成一個(gè)事件”。name 參數(shù)(arguments)是事件的名稱,[...data] 是可選的帶有事件數(shù)據(jù)的其他參數(shù)(arguments)。
  • 此外還有 .on(name, handler) 方法,它為具有給定名稱的事件添加了 handler 函數(shù)作為監(jiān)聽器(listener)。當(dāng)具有給定 name 的事件觸發(fā)時(shí)將調(diào)用該方法,并從 .trigger 調(diào)用中獲取參數(shù)(arguments)。
  • ……還有 .off(name, handler) 方法,它會(huì)刪除 handler 監(jiān)聽器(listener)。

添加完 mixin 后,對(duì)象 user 將能夠在訪客登錄時(shí)生成事件 "login"。另一個(gè)對(duì)象,例如 calendar 可能希望監(jiān)聽此類事件以便為登錄的人加載日歷。

或者,當(dāng)一個(gè)菜單項(xiàng)被選中時(shí),menu 可以生成 "select" 事件,其他對(duì)象可以分配處理程序以對(duì)該事件作出反應(yīng)。諸如此類。

下面是代碼:

  1. let eventMixin = { 
  2.   /** 
  3.    * 訂閱事件,用法: 
  4.    *  menu.on('select'function(item) { ... } 
  5.   */ 
  6.   on(eventName, handler) { 
  7.     if (!this._eventHandlers) this._eventHandlers = {}; 
  8.     if (!this._eventHandlers[eventName]) { 
  9.       this._eventHandlers[eventName] = []; 
  10.     } 
  11.     this._eventHandlers[eventName].push(handler); 
  12.   }, 
  13.  
  14.   /** 
  15.    * 取消訂閱,用法: 
  16.    *  menu.off('select', handler) 
  17.    */ 
  18.   off(eventName, handler) { 
  19.     let handlers = this._eventHandlers?.[eventName]; 
  20.     if (!handlers) return
  21.     for (let i = 0; i < handlers.length; i++) { 
  22.       if (handlers[i] === handler) { 
  23.         handlers.splice(i--, 1); 
  24.       } 
  25.     } 
  26.   }, 
  27.  
  28.   /** 
  29.    * 生成具有給定名稱和數(shù)據(jù)的事件 
  30.    *  this.trigger('select', data1, data2); 
  31.    */ 
  32.   trigger(eventName, ...args) { 
  33.     if (!this._eventHandlers?.[eventName]) { 
  34.       return; // 該事件名稱沒有對(duì)應(yīng)的事件處理程序(handler) 
  35.     } 
  36.  
  37.     // 調(diào)用事件處理程序(handler) 
  38.     this._eventHandlers[eventName].forEach(handler => handler.apply(this, args)); 
  39.   } 
  40. }; 

  1. .on(eventName, handler) — 指定函數(shù) handler 以在具有對(duì)應(yīng)名稱的事件發(fā)生時(shí)運(yùn)行。從技術(shù)上講,這兒有一個(gè)用于存儲(chǔ)每個(gè)事件名稱對(duì)應(yīng)的處理程序(handler)的 _eventHandlers 屬性,在這兒該屬性就會(huì)將剛剛指定的這個(gè) handler 添加到列表中。
  2. .off(eventName, handler) — 從處理程序列表中刪除指定的函數(shù)。
  3. .trigger(eventName, ...args) — 生成事件:所有 _eventHandlers[eventName] 中的事件處理程序(handler)都被調(diào)用,并且 ...args 會(huì)被作為參數(shù)傳遞給它們。

用法:

  1. // 創(chuàng)建一個(gè) class 
  2. class Menu { 
  3.   choose(value) { 
  4.     this.trigger("select", value); 
  5.   } 
  6. // 添加帶有事件相關(guān)方法的 mixin 
  7. Object.assign(Menu.prototype, eventMixin); 
  8.  
  9. let menu = new Menu(); 
  10.  
  11. // 添加一個(gè)事件處理程序(handler),在被選擇時(shí)被調(diào)用: 
  12. menu.on("select", value => alert(`Value selected: ${value}`)); 
  13.  
  14. // 觸發(fā)事件 => 運(yùn)行上述的事件處理程序(handler)并顯示: 
  15. // 被選中的值:123 
  16. menu.choose("123"); 

 現(xiàn)在,如果我們希望任何代碼對(duì)菜單選擇作出反應(yīng),我們可以使用 menu.on(...) 進(jìn)行監(jiān)聽。

使用 eventMixin 可以輕松地將此類行為添加到我們想要的多個(gè)類中,并且不會(huì)影響繼承鏈。

三、總結(jié)

Mixin — 是一個(gè)通用的面向?qū)ο缶幊绦g(shù)語:一個(gè)包含其他類的方法的類。

一些其它編程語言允許多重繼承。JavaScript 不支持多重繼承,但是可以通過將方法拷貝到原型中來實(shí)現(xiàn) mixin。

我們可以使用 mixin 作為一種通過添加多種行為(例如上文中所提到的事件處理)來擴(kuò)充類的方法。

如果 Mixins 意外覆蓋了現(xiàn)有類的方法,那么它們可能會(huì)成為一個(gè)沖突點(diǎn)。因此,通常應(yīng)該仔細(xì)考慮 mixin 的命名方法,以最大程度地降低發(fā)生這種沖突的可能性。

 

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2025-06-11 10:00:00

多繼承MixinPython

2012-07-10 01:59:12

設(shè)計(jì)模式

2015-10-08 10:13:23

JavaScriptnginScript

2012-12-18 10:03:22

JavaScriptWebJS

2012-06-29 09:56:57

設(shè)計(jì)模式

2021-10-29 09:40:21

設(shè)計(jì)模式軟件

2023-10-30 10:20:45

2012-10-29 11:16:13

2021-02-19 14:07:03

JavaScript編程開發(fā)

2012-12-25 09:38:41

JavaScript設(shè)計(jì)模式

2010-09-13 09:18:22

JavaScript模塊模式

2022-06-02 12:02:12

V8C++JavaScript

2015-09-08 13:39:10

JavaScript設(shè)計(jì)模式

2012-02-29 09:41:14

JavaScript

2011-05-26 13:43:30

MongoDB

2017-03-15 08:43:29

JavaScript模板引擎

2017-03-20 17:59:19

JavaScript模板引擎

2021-11-09 08:51:13

模式命令面試

2021-11-05 07:47:56

代理模式對(duì)象

2021-11-02 22:04:58

模式
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 福利片在线观看 | 国产激情偷乱视频一区二区三区 | 免费麻豆视频 | 亚洲精品一区中文字幕乱码 | 欧美日韩黄色一级片 | 日日草天天干 | 一区二区三区在线免费看 | 国产精品夜色一区二区三区 | 国产精品美女一区二区 | 天天操人人干 | 亚洲国产69 | 免费人成在线观看网站 | 日韩在线一区二区三区 | 免费色网址 | 午夜精品久久 | 久久中文字幕一区 | 成人欧美一区二区三区在线播放 | 国产精品久久影院 | 欧美不卡在线 | 日韩精品免费 | 亚洲综合在 | 国产福利在线 | 国产国产精品 | 涩涩鲁亚洲精品一区二区 | 欧美一卡二卡在线 | 99精品欧美一区二区蜜桃免费 | 免费在线观看av网址 | 日本视频在线 | 麻豆久久 | 久久这里只有精品首页 | 久久久久国产一区二区三区四区 | 国产日韩欧美在线观看 | 黄色片视频免费 | 亚洲日日夜夜 | 日韩欧美精品一区 | 成人亚洲| 91免费观看国产 | 黄色大片在线免费观看 | 成人日韩| 91一区二区在线观看 | 在线一区视频 |