javascript中模塊化知識總結

JavaScript 模塊化開發


1. 模塊化介紹

掌握模塊化基本概念以及使用模塊化帶來的好處html

當你的網站開發愈來愈複雜的時候,會常常遇到什麼問題?前端

  • 惱人的命名衝突
  • 繁瑣的文件依賴

歷史上,JavaScript一直沒有模塊(module)體系, 沒法將一個大程序拆分紅互相依賴的小文件,再用簡單的方法拼裝起來。 其餘語言都有這項功能,好比Ruby的 require、Python的 import , 甚至就連CSS都有 @import , 可是JavaScript任何這方面的支持都沒有,這對開發大型的、複雜的項目造成了巨大障礙。jquery

如何解決不經過 script 標籤就能加載 JavaScript 文件代碼。git

  • 什麼是模塊化github

    • 一起一起的:JavaScript 也是一起一起
    • 模塊化就是一種將復瑣事物按照模塊的方式簡單化實現
    • 模塊與模塊之間互相協做構成了模塊系統
  • 使用模塊化開發的方式帶來的好處面試

    • 生產效率高
    • 可維護性高

眼見他起高樓,眼見他宴賓客,眼見他樓塌了。ajax


2. 模塊化開發演變

體驗刀耕火種的模塊化解決方式npm

2.1 全局函數

  • 污染了全局變量
  • 模塊成員之間看不出直接關係

2.2 命名空間

  • 理論意義上減小了變量衝突
  • 缺點1:暴露了模塊中全部的成員,內部狀態能夠被外部改寫,不安全
  • 缺點2:命名空間會愈來愈長

2.3 私有空間

  • 私有空間的變量和函數不會影響全局做用域
  • 公開公有方法,隱藏私有屬性

2.4 模塊的維護和擴展

  • 開閉原則
  • 可維護性好

2.5 模塊的第三方依賴

  • 保證模塊的獨立性
  • 模塊之間的依賴關係變得明顯

2.6 總結

之後若是不使用第三方規範的狀況下, 若是寫模塊能夠採用下面這種方式編程

```js ; (function (形參模塊名, 依賴項, 依賴項) { // 經過 形參模塊名 修改模塊數組

window.模塊名 = 形參模塊名 })(window.模塊名 || {}, 依賴項, 依賴項) ```

下面是一個關於模塊化的面試題,一塊兒觀察和分析這段代碼的做用:

js var UTIL = (function (parent, $) { // 動態的給一個不存在的對象掛載一個子對象 var my = parent.ajax = parent.ajax || {} my.get = function (url, params, callback) { return $.getJSON(url, params, callback) } return parent }(UTIL || {}, jQuery))


3. 模塊化規範

3.1 模塊系統理解

天然界生態系統、計算機操做系統、軟件辦公系統,還有教育系統、金融系統、網絡系統、 理論系統等等。究竟什麼是系統呢?

維基百科:系統泛指由一羣有關連的個體組成,根據預先編排好的規則工做, 能完成個別元件不能單獨完成的工做的羣體。 系統分爲天然系統與人爲系統兩大類。

簡單來講,系統有兩個基本特性:

  1. 系統由個體組成
  2. 個體之間有關聯,按照規則協同完成任務

系統之間的個體能夠成爲系統成員,要構建一個系統,最基本的層面須要作兩件事:

  1. 定義系統成員:肯定成員是什麼
    • 模塊是一個 JavaScript 文件
    • 每個模塊都使用 define 函數去定義
  2. 約定系統通信:肯定成員之間如何交互,遵循的規則是什麼
    • 一個 SeaJS 模塊默認就是私有做用域
    • 若是想要被外部文件模塊所訪問,就必須把要公開的屬性掛載給 module.exports 對象接口
    • 使用 require 函數能夠加載一個指定的模塊,獲得該模塊代碼中暴露的接口對象
  3. 如何啓動整個模塊系統
    • 在 html 頁面中使用 seajs.use() 方法,指定一個入口文件模塊

Sea.js 是一個適用於 Web 瀏覽器端的模塊加載器。 在 Sea.js 裏,一切皆是模塊,全部模塊協同構建成模塊系統。 Sea.js 首要要解決的是模塊系統的基本問題:

  1. 模塊是什麼?
  2. 模塊之間如何交互?

在前端開發領域,一個模塊,能夠是JS 模塊,也能夠是 CSS 模塊,或是 Template 等模塊。 而 Sea.js 則專一於 JS 文件模塊:

  1. 模塊是一段 JavaScript 代碼,具備統一的 基本書寫格式
  2. 模塊之間經過基本 交互規則 ,能彼此引用,協同工做

把上面兩點中說起的基本書寫格式和基本交互規則描述清楚,就能構建出一個模塊系統。 對書寫格式和交互規則的詳細描述,就是模塊定義規範(Module Definition Specification)。

好比 CommonJS 社區的 Modules 1.1.1 規範, 以及 NodeJS 的 Modules 規範, 還有 RequireJS 提出的 AMD 規範等等。

Sea.js 遵循的是 CMD 規範。

3.2 常見的 JavaScript 模塊化規範

  • CommonJS
    • Node.js
  • AMD
    • RequireJS
  • CMD Common Module Definition
    • CMD 就是 SeaJS 這個模塊加載器在推廣的過程當中定義的一個模塊規範
  • ECMAScript
    • ECMAScript 6
  • UMD

CMD、AMD、CommonJS 都是社區制定出來的模塊規範, 他們的目的都是爲了解決 JavaScript 沒有模塊化系統的問題。 他們都有如何定模塊成員,以及模塊成員之間如何進行通訊交互的規則。

AngularJS Module 也是 ng 框架自己提供的一個模塊系統解決方案。 ng定義模塊須要起名,即使你去加載或者依賴一個模塊的時候, 這個被依賴的模塊也須要經過 script 標籤引入到 html 頁面中。

2015 年 9 月份,ECMAScript 官方推出了 ECMAScript 6 語言標準。 在最新的 ES6 語言規範標準中,已經制定了 JavaScript 模塊化規範。

export import

前端界的風氣:都喜歡追趕新技術,甚至把沒有推出來的標準直接幹到了生產環境。

這個社區太浮躁了。


4. SeaJS

A Module Loader for the Web, Enjoy the fun of programming.

  • 提供簡單、極致的模塊化開發體驗
  • A Module Loader for the Web
  • JavaScript 模塊加載器
  • 能夠實現 在 JavaScript 代碼中去加載另外一個 JavaScript 代碼。

4.1 SeaJS 介紹

  • 關於 SeaJS

    • SeaJS 是一個適用於瀏覽器環境的 JavaScript 模塊加載器
    • 一個庫文件,相似於 jQuery
    • 使用這個庫提供的規範的模塊化的方式來編寫 JavaScript 代碼
    • 只關心 JavaScript 文件代碼模塊如何組織
      • 只關心 JavaScript 文件之間如何相互協議、引用、依賴
    • SeaJS 的做者是阿里巴巴支付寶前端架構師,花名:玉伯,玉伯也叫射鵰
    • Sea.js創始人玉伯的前端開發之路
    • SeaJS
    • SeaJS -github
  • 爲何學習和使用 SeaJS ?

    • 簡單友好的模塊定義規範:SeaJS 遵循 CMD 規範,能夠像 Node 同樣書寫模塊代碼
    • 天然直觀的代碼組織方式:依賴的自動加載、配置簡潔清晰,可讓咱們更多的享受編碼的樂趣
    • SeaJS兼容性很是好,幾乎能夠運行在任何瀏覽器引擎上
    • 注1:SeaJS 只是實現模塊化開發的一種方式或者說一種工具而已,重在模塊化思想的理解
    • 注2:由於 SeaJS 採用的 CMD 模塊規範和 Node 中的 CommonJS 模塊規範很是一致,因此有利於咱們學習 Node 中的模塊化編程
  • 誰在用?

    • 淘寶網、支付寶、京東、愛奇藝。。。
  • SeaJS 適用場景

    • 沒有使用任何框架,例如 AngularJS
    • 例如 只寫寫 原生 JavaScript 或者用了一些第三方庫
    • SeaJS 不提供任何功能性 API,只提供瞭解決 JavaScript 代碼的命名污染和文件依賴的問題

4.2 快速上手(Getting Started)

  1. 下載 sea.js 庫文件
  2. 在頁面中引入 sea.js
  3. 使用 define 函數定義模塊
  4. 使用 require 函數加載模塊
  5. 使用 module.exports 對外暴露接口對象
  6. 使用 seajs.use 函數啓動模塊系統

4.3 API 詳解

4.3.1 seajs.use

加載模塊,啓動模塊系統。

  • 加載一個模塊 seajs.use('id')
  • 加載一個模塊,在加載完成時,執行回調 seajs.use('id', callback)
  • 加載多個模塊,加載完成時,執行回調 seajs.use(['id1','id2',...],callback)

  • 注意:

    • 在調用 seajs.use 以前,須要先引入 sea.js 文件
    • seajs.use 與 DOM ready 事件沒有任何關係。若是某些操做要確保在 DOM ready 後執行,須要使用 jquery 等類庫來保證
    • seajs.use 理論上只用於加載啓動,不該該出如今 define 中的模塊代碼裏

4.3.2 define(factory)

define 是一個全局函數,用來定義模塊。

define 接受 factory 參數,factory 能夠是一個函數,也能夠是一個對象或字符串。

factory 爲對象、字符串時,表示模塊的接口就是該對象、字符串。

  • factory 是一個對象時

    • define({})
  • factory 是一個字符串時

    • define('hello')
  • factory 是一個函數時

    • define(function(require, exports, module){})

4.3.3 require

require 用來加載一個 js 文件模塊, require 用來獲取指定模塊的接口對象 module.exports

require 在加載和執行的時候,js 會按照同步的方式和執行。

使用注意:

  • 正確拼寫
    • 模塊 factory 構造方法的第一個參數 必須 命名爲 require
  • 不要修改
    • 不要重命名 require 函數,或在任何做用域中給 require 從新賦值
  • 使用字符串直接量
    • require 的參數值 必須 是字符串直接量

Tips: 把 require 看作是語法關鍵字就好啦

4.3.4 模塊標識

模塊標識是一個字符串,用來標識模塊。

  • 模塊標識能夠不包含文件後綴名,好比 .js

    • seajs 推薦不加 .js 文件模塊後綴
  • 模塊標識能夠是 相對 或 頂級 標識

  • 相對標識

相對標識以 . 開頭,永遠相對於當前模塊所處的路徑來解析。

  • 頂級標識

頂級標識不以 . 或 / 開始,會相對模塊系統的基礎路徑(base路徑,默認是 sea.js 文件所屬的路徑)。 能夠手動配置 base 路徑。

js seajs.config({ base: './js' })

  • 普通路徑

除了相對和頂級標識以外的標識都是普通路徑。 普通路徑的解析規則,會相對當前頁面解析。

```js // 假設當前頁面是 http://example.com/path/to/page/index.html

// 絕對路徑是普通路徑: require.resolve('http://cdn.com/js/a'); // => http://cdn.com/js/a.js

// 根路徑是普通路徑: require.resolve('/js/b'); // => http://example.com/js/b.js

// use 中的相對路徑始終是普通路徑: seajs.use('./c'); // => 加載的是 http://example.com/path/to/page/c.js

seajs.use('../d'); // => 加載的是 http://example.com/path/to/d.js ```

Tips:

  • 頂級標識始終相對 base 基礎路徑解析。
    • 若是不設置,base 路徑默認就是 sea.js 庫文件所屬的路徑
    • 能夠經過 seajs.config({ base: '基礎路徑' }) 來配置基礎路徑
  • 絕對路徑和根路徑始終相對當前頁面解析。
  • 相對標識永遠相對於當前文件
  • seajs.use 中的相對路徑始終相對當前頁面來解析。

4.3.5 module

module 是一個對象,上面存儲了與當前模塊相關聯的一些屬性和方法。

  • module.id
    • 模塊的惟一標識,能夠經過 define 方法的第一個參數來指定,默認爲該模塊文件的絕對路徑
  • module.uri
    • 模塊的絕對路徑
  • module.dependencies
    • dependencies 是一個數組,表示當前模塊的依賴
  • module.exports
    • 當前模塊對外提供的接口對象
    • 至關於每一個模塊內部最終都執行了這麼一句話:return module.exports
    • 模塊與模塊之間的通訊接口

4.3.6 exports

exports 僅僅是 module.exports 的一個引用。 也就是說修改了 exports 就至關於修改了 module.exports。

可是一旦在 factory 內部給 exports 從新賦值,並不會改變 module.exports 的值。 所以給 exports 賦值是無效的。

4.4 exports 和 module.exports 的區別

  • 每一個模塊內部對外處處的接口對象始終都是 module.exports
  • 能夠經過修改 module.exports 或給它賦值改變模塊接口對象
  • exports 是 module.exports 的一個引用,就比如在每個模塊定義最開始的地方寫了這麼一句代碼:var exports = module.exports

關於這倆哥們兒的區別請分析一下代碼:

```js var module = { exports: {} }

function changeExports (exports, module) { // var exports = module.exports exports.foo = 'bar'

// 這裏賦值拿不到,不要使用使用 // exports = function () {} return module.exports }

changeExports(module.exports, module) ```

那爲啥要有 exports ?

爲了開發體驗,API更友好,使用 exports 的時候,能夠少寫一個點兒。

若是你實在分不清楚 exports 和 module.exports 之間的區別,就只記得 module.exports 就能夠了。

相關文章
相關標籤/搜索