JavaScript組件模式深入淺出

2021-01-07 51CTO

「組件模式」是一種很常用的Javascript編碼模式。雖然已經被廣泛的應用,但是還有一些高級的用途沒有被關注。在這邊文章裡,我將針對幾個比較特別的話題進行簡單的闡述,其中的一些我認為應該是***次被提及。

基礎

我們從一個簡單的組件模式開始說起,這個模式現在已經非常流行,最初是3年前由雅虎YUI的Eric Miraglia在其博客中提出的。如果你已經對這個模式很熟悉了,那麼可以直接跳到「高級模式」一節。

匿名閉包(Anonymous Closures)

這是使得模式可以正常工作的語言基礎,也實在是javascript最為實用的特性之一。我們可以簡單的創建一個匿名函數,並且立刻執行它。所有運行在該函數裡的代碼叫做一個閉包,它提供了在整個應用程式生命周期中都有效的數據隱私控制以及狀態保存功能。

(function () {          }()); 

請注意()包圍了匿名函數,這是語法的需要,因為以function開頭的語句會被編譯器認為的函數的定義,而加上()就變為了創建了一個函數表達式。

全局導入(Global Import)

JavaScript 有一個大家熟知的特性叫做implied globals,就是當使用一個變量的時候,解釋器會沿著作用域鏈一直向上查找這個變量的定義,如果沒找到,這個變量就會自動成為一個全局(global)變量。這意味著在一個匿名閉包裡去創建一個全局變量變得非常簡單。

但是,這產生了很難管理的代碼問題,因為我們無法明顯的知道一個給定的文件裡究竟哪些變量是全局的

(譯者註:如果允許這麼隱晦的寫法來創建全局變量,則代碼中使用的變量,很難知道是全局的還是局部的。)

幸運的是,我們的匿名函數提供了一個很簡單的修改來解決這個問題。我們傳入一個全局對象作為匿名函數的參數,我們利用這個參數導入我們的變量到全局對象中,這樣做比隱式的聲明全局變量要乾淨和快速的多。下面是一個例子

(function ($, YAHOO) {           }(jQuery, YAHOO)); 

模塊導出(Module Export)

有時候我們不只是想定義一個模塊,還想直接使用它,我們可以使用匿名函數的返回值來實現。如果這麼做,就是實現了一個基本的「組件模式」,看下面的例子:

var MODULE = (function () {          var my = {},privateVariable = 1;                  function privateMethod() {                   }  my.moduleProperty = 1;          my.moduleMethod = function () {                   };                  return my;  }()); 

要注意的是我們定義了一個全局組件名字叫「MODULE」,他有兩個屬性:一個方法MODULE.moduleMethod以及一個屬性MODULE.moduleProperty。並且,它通過匿名函數所在的閉包維護了一組私有的內部狀態

(譯者註:privateVariable變量和privateMethod方法都是私有的,外部無法訪問)。

這樣的話,我們就可以用上面的模式簡單的導入需要的全局變量。

高級模式(Advanced Patterns)

上面的模式已經可以解決應用中的許多問題,但是我們還可以在這個基礎上擴展出很多強大的,易擴展的結構。讓我們一個個看一下,繼續用我們的組件「MODULE」做例子

增益模式(Augmentation)

使用上面的模式的缺點和限制之一,就是整個模塊必須在一個文件裡。任何在大型項目中工作的人都會意識到能將代碼拆分成多個文件帶來的價值。幸運的是,我們有一個不錯的解決方案叫做「增益組件」。首先,我們導入組件,然後添加屬性,然後再將其導出。下面是一個例子,為我們的MODULE組件添加增益特性:

var MODULE = (function (my) {          my.anotherMethod = function () {                   };          return my;  }(MODULE)); 

我們使用var關鍵字來保持一致性(儘管這不是必須的)。這段代碼執行過後,我們的組件就增加了一個公開的方法叫做MODULE.anotherMethod。這個增加的文件也會同時保持它自己的私有狀態。

(譯者註:通過增益模式,一個雷被切分成獨立的文件,每個文件關注它內部需要的方法和屬性,並且當所有文件合併執行後,可以成為一個完整的組件)

鬆耦合增益(Loose Augmentation)

我們上面的例子有一個缺點,就是需要MODULE模塊先被創建,然後再執行子文件中的增益。這是一種緊耦合的做法。javascript性能優化中通常的做法是腳本的異步加載,這樣我們就可以創建由多個文件組成的易擴展的組件,並且他們可以以任何順序來加載,這叫做鬆耦合增益模式:

var MODULE = (function (my) {            return my;  }(MODULE || {})); 

在這個模式中,var關鍵字是必須的。注意我們的import點(參數)會自動判斷組件是否存在,否則就創建一個空組件。這意味著你可以使用一些異步加載工具比如LABjs來並行加載你所有的js組件,而不需要block頁面。

緊耦合增益(Tight Augmentation)

「鬆耦合增益」模式非常棒,不過它也有一些限制,最重要的一個就是無法重寫屬性。你也無法在初始化組件的時候使用其他文件的內容(因為加載順序無法保證),「緊耦合增益模式」需要一個有序的加載順序,但是允許你重寫其他文件的內容,這是一個簡單的例子:

var MODULE = (function (my) {          var old_moduleMethod = my.moduleMethod;                  my.moduleMethod = function () {                    };                  return my;  }(MODULE)); 

這裡我們重寫了 MODULE.moduleMethod,同時也保存了舊的 MODULE.moduleMethod方法的引用(如果需要的話)

克隆和繼承(Cloning and Inheritance)

var MODULE_TWO = (function (old) {          var my = {}, key;                  for (key in old) {                  if (old.hasOwnProperty(key)) {                          my[key] = old[key];                  }          }                  var super_moduleMethod = old.moduleMethod;          my.moduleMethod = function () {                   return my;  }(MODULE)); 

這種模式也許是最沒有擴展性的選項了。它雖然看上去讓代碼更簡潔,但是帶來的是擴展性的損失。我們上面的代碼中,所有的屬性和方法都不是副本,他們以「一個對象2個引用」的方式存在。修改其中一個都會影響到另外一個。

跨文件私有狀態(Cross-File Private State)

將組件分割到多個文件中的另外一個限制,就是每個文件只能訪問他自己的私有狀態,而沒有權限訪問其他文件的私有數據。這個問題可以解決,下面是一個「鬆耦合增益模式」的跨文件訪問私有狀態的版本:

var MODULE = (function (my) {          var _private = my._private = my._private || {},                  _seal = my._seal = my._seal || function () {                          delete my._private;                          delete my._seal;                          delete my._unseal;                  },                  _unseal = my._unseal = my._unseal || function () {                          my._private = _private;                          my._seal = _seal;                          my._unseal = _unseal;                  };                   return my;  }(MODULE || {})); 

現在任何文件都可以在本地變量_private中設置屬性,並且會立即將設置結果反饋給其他文件。一旦組件加載完成,應用程式應該調用 MODULE._seal()方法,這個方法會阻止外部程序訪問內部屬性_private。如果這個組件被其他文件進行了擴展(增益),則可在加載新的文件之前,調用_unseal()方法解封,然後在文件加載完之後調用_seal()再次將類對外部屏蔽。

(譯者註:注意_unseal方法會在對象裡添加1個公開的屬性和2個公開方法,其他文件就可以在my對象中隊private屬性進行擴展,然後利用_seal()方法刪除公開的屬性,保持對象的密封性)

這個模式是今天我在工作的時候想到的,我沒有在其他地方見過這種用法,我認為這是一種十分有用的模式。

子模塊(Sub-modules)

Our final advanced pattern is actually the simplest. There are many good cases for creating sub-modules. It is just like creating regular modules:

我們***的一個高級模式實際上是最簡單的,創建子模塊有很多的好處,創建子模塊就和創建普通模塊一樣:

MODULE.sub = (function () {          var my = {};           return my;  }()); 

雖然這很簡單,但我還是認為子模塊應該包含進來,因為子模塊擁有所有正常模塊有的高級特性,包括增益和私有數據保存。

結論

大多數高級模式都可以結合起來使用,如果是我的話,我比較喜歡把「鬆耦合增益」、「私有狀態保存」、「子模式」結合起來使用

我這篇文字並沒有討論性能相關的內容,不過我想簡單的說一下:組件模式是對性能有好處的。因為它確實讓下載快了很多:使用「鬆耦合增益」模式可以讓腳本並行的無阻塞加載,這加快了下載速度。整體初始化完成的時間也許比其他方法慢了一些,不過這是值得的。

作為結尾,這裡有一個子模塊的例子,他動態的加載自己到它的父模塊中。這個模式允許整個模塊並行的加載自己,以及自己的子模塊。

譯文出自:刺客之家的博客

原文連結:http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

【編輯推薦】

JavaScript面向對象編程 JavaScript繼承詳解 早該知道的7個JavaScript技巧 JavaScript MVC框架backbone.js初探 8個***的JavaScript腳本資源強烈推薦

【責任編輯:

陳貽新

TEL:(010)68476606】

點讚 0

相關焦點

  • 如何使用JavaScript實現前端導入和導出excel文件
    1.2 實現一鍵導入excel文件並生成table表格導入excel文件的功能我們可以用javascript原生的方式實現解析, 比如可以用fileReader這些原生api,但考慮到開發效率和後期的維護, 筆者這裡採用antd的Upload組件和XLSX來實現上傳文件並解析的功能.
  • 工作原理|組件活門的三種流量模式
    本文轉載自【微信公眾號:我愛修飛機,ID:csnnng】經微信公眾號授權轉載,如需轉載與原文作者聯繫如下圖,線圈C通電,控制氣壓通向活門作動筒A腔和流量伺服組件。A腔的氣壓克服作動筒隔膜彈力使活門打開。
  • 前端組件/庫打包利器rollup使用與配置實戰
    前言寫rollup的文章是因為筆者最近要規範前端開發的業務流程和架構,並提供內部公有組件庫和工具庫供團隊使用。如果用webpack做,雖然可以實現tree-shaking,但是需要自己配置並且打包出來的代碼非常臃腫,所以對於庫文件和UI組件,rollup更加適合。
  • 《前端5分鐘》之迭代器模式的N+1種應用場景
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫你將學到迭代器模式的含義實現一個數組迭代器其實javascript中的很多方法都運用了迭代器的思想,比如數組的forEach,every,find,some,map,entries等等,這些操作極大的簡化了我們的邏輯操作,接下來我們就來看看它的具體應用吧。
  • 對付流氓組件,必須開啟上帝模式!
    它也有很多強大的功能,但無用的組件越來越多,比較浪費時間和精力。安卓 - 上帝模式嗶哩嗶哩開啟上帝模式能幹些什麼?先安裝 「太極」,再安裝 「上帝模式」,等全部安裝完成後再運行 「太極」 APP在太極「模塊管理」中將「上帝模式」勾選將要修改的應用加載到太極中,莫理用網易雲舉例
  • 20個常用的JavaScript簡寫技巧
    當你在 React 中想要有條件地渲染某個組件時,這個短路寫法比較有用。例如: 6. 交換兩個變量 為了交換兩個變量,我們通常使用第三個變量。我們可以使用數組解構賦值來交換兩個變量。 7.
  • 用Java語言巧妙實現javascript的運行
    Java前言在學習開發的過程中javascript是每位程式設計師小盆友都得掌握的一種方法,他們可以說是貫穿了整個Java開發的語言,下面給大家演示一下在Java中如何完美運行javascript案例,跟著小編一起來學習一下吧
  • 初識javascript,JS的歷史_騰訊新聞
    javascript和H5的關關係 什麼是HTML5? javascript的應用範圍 1.PC端web開發(網站) 2.移動端開發(webApp、混合App)服務端開發(NodeJs) 3.遊戲開發(unity3D-TypeScript,網頁遊戲)在線演示:忍者水果
  • 2020年最熱度最高的5個JavaScript框架
    React5.Polymer沒錯Polymer是Google的另一個javascript框架,該框架通過建立和重新使用Web組件的能力來創建現代Web設計,從而使其變得超快。該聚合物是一個輕量級的庫,可以幫助開發人員充分利用Web組件。其實在Javascript中有著更多的優秀框架,這裡只提到了常用的幾種,如果您不熟悉JavaScript框架或JavaScript程式語言,則可以快速進行嘗試並嘗試使用上述任何JS框架,因為它們都是免費易用的。如果你有更好的提議,不妨在評論區一起提出討論。
  • Javascript.info - 更新頻率極高的Javascript免費開源電子教程
    Javascript.info 首頁截圖Javascript.info 依託 learn.javascript.ru 而來的,learn.javascript.ru 是俄羅斯最大的 JavaScript 教程和學習平臺之一。
  • 九個難以置信的HTML5和JavaScript實驗
    一款javascript遊戲,點擊和控制藍色的盒子,讓黃色的點擊不要碰到紅色的點。       5.Sketch 3D   模仿水族館,您可以創建豐富多彩,充滿活力的運動模式。         8. Ultra Neuron Pong
  • JavaScript小知識:String類型
    let lang="java";lang=lange+"scriot";console.log(lang);//javascript我們首先創建變量lang用來保存字符串java,然後我們將lang保存的字符串改為由原先保存字符串java和新的字符串
  • Javascript去除字符串中的點或其他符號
    在前端上使用javascript進行操作的。測試了兩次沒有好用,程序直接把整個字符串都進行了替換,在考慮這個是為什麼呢?javascript(請忽略此配圖)示例var ip = data.field.ip.replace(/.
  • 幾個非常有意思的javascript知識點總結
    這個問題主要是之前有朋友問過我,當時的想法就是簡單的認為script內的代碼執行完之後以及與dom綁定了,存放在了瀏覽器內存中,最近查了很多資料發現有一個有點意思的解釋,放出來大家可以感受一下:JavaScript解釋器在執行腳本時,是按塊來執行的,也就是說瀏覽器在解析HTML文檔流時,如果遇到一個script標籤,javascript
  • 第一篇:JavaScript基本語法
    html><head><title>這是登錄頁面</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><script type="text/javascript
  • 第五篇:JavaScript事件處理
    庫的網頁代碼(案例代碼見unit12\case1.html):<html><head><title>JavaScript開發案例</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><script type="text/javascript
  • 面對五花八門的組件,2021年戶用市場組件如何選擇?
    作為戶用光伏系統中價值佔比接近60%的核心部件,光伏組件的選型至關重要,直接影響項目的發電量及投資收益。同時面對廣闊的戶用光伏市場,2020年以來各大光伏組件廠家陸續推出各式各樣的光伏組件,以滿足日益增長的戶用市場需求。目前戶用光伏市場光伏組件規格型號繁多,按照不同的分類方式有不同的結果。
  • 前端:用javascript實現一個轉盤小遊戲?
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫本文主要介紹如何使用原生javascript和Css3來實現一個在各大移動應用中經常出現的轉盤遊戲,由於改實現可以有不同方式,如果熟悉canvas的話也可以用canvas實現,本文採用js和css實現主要考慮到複雜度較小性能較好
  • 資料| 深入淺出 Python(中文版)
    《深入淺出Python))通過一種獨特的超越語法手冊的方式來幫助你學習Python。你將能夠快速掌握Python的基礎知識,然後擴展到持久化、異常處理、Web開發、SQLite、數據處理和Google應用引擎中去。你也將學會如何為Android編寫移動應用,這要感謝Pvthon帶給你的強大能力。《深入淺出Python》融合了完備的學習經驗,它將幫助你成為真正的Python編程員。