天天看點

♣ 子產品化開發

♠ 什麼是子產品化

到底什麼是子產品化、子產品化開發呢?

  1. 事實上子產品化開發最終的目的是将程式劃分成一個個小的結構;
  2. 這個結構中編寫屬于自己的邏輯代碼,有自己的作用域,不會影響到其他的結構;
  3. 這個結構可以将自己希望暴露的變量、函數、對象等導出給其結構使用;
  4. 也可以通過某種方式,導入另外結構中的變量、函數、對象等;

上面說提到的結構,就是子產品;按照這種結構劃分開發程式的過程,就是子產品化開發的過程;

無論你多麼喜歡JavaScript,以及它現在發展的有多好,它都有很多的缺陷:

  1. 比如var定義的變量作用域問題;
  2. 比如JavaScript的面向對象并不能像正常面向對象語言一樣使用class;
  3. 比如JavaScript沒有子產品化的問題;

Brendan Eich本人也多次承認過JavaScript設計之初的缺陷,但是随着JavaScript的發展以及标準化,存在的缺陷問題基本都得到了完善。無論是web、移動端、小程式端、伺服器端、桌面應用都被廣泛的使用;

♠ 子產品化的曆史

       在網頁開發的早期,Brendan Eich開發JavaScript僅僅作為一種腳本語言,做一些簡單的表單驗證或動畫實作等,那個時候代碼還是很少的:這個時候我們隻需要講JavaScript代碼寫到<script>标簽中即可;并沒有必要放到多個檔案中來編寫;甚至流行:通常來說 JavaScript 程式的長度隻有一行。但是随着前端和JavaScript的快速發展,JavaScript代碼變得越來越複雜了:ajax的出現,前後端開發分離,意味着後端傳回資料後,我們需要通過JavaScript進行前端頁面的渲染;SPA的出現,前端頁面變得更加複雜:包括前端路由、狀态管理等等一系列複雜的需求需要通過JavaScript來實作;包括Node的實作,JavaScript編寫複雜的後端程式,沒有子產品化是緻命的硬傷;是以,子產品化已經是JavaScript一個非常迫切的需求:但是JavaScript本身,直到ES6(2015)才推出了自己的子產品化方案;在此之前,為了讓JavaScript支援子產品化,湧現出了很多不同的子產品化規範:AMD、CMD、CommonJS等;在我們的課程中,我将詳細講解JavaScript的子產品化,尤其是CommonJS和ES6的子產品化。

早期沒有子產品化帶來了很多的問題:比如命名沖突的問題,當然,我們有辦法可以解決上面的問題:立即函數調用表達式(IIFE) ,IIFE (Immediately Invoked Function Expression)但是,我們其實帶來了新的問題:

  • 第一,我必須記得每一個子產品中傳回對象的命名,才能在其他子產品使用過程中正确的使用;
  • 第二,代碼寫起來混亂不堪,每個檔案中的代碼都需要包裹在一個匿名函數中來編寫;
  • 第三,在沒有合适的規範情況下,每個人、每個公司都可能會任意命名、甚至出現子產品名稱相同的情況;

是以,我們會發現,雖然實作了子產品化,但是我們的實作過于簡單,并且是沒有規範的。 我們需要制定一定的規範來限制每個人都按照這個規範去編寫子產品化的代碼;這個規範中應該包括核心功能:子產品本身可以導出暴露的屬性,子產品又可以導入自己需要的屬性;JavaScript社群為了解決上面的問題,湧現出一系列好用的規範,接下來我們就學習具有代表性的一些規範。

♣ 子產品化開發

♠ CommonJS規範和Node關系

我們需要知道CommonJS是一個規範,最初提出來是在浏覽器以外的地方使用,并且當時被命名為ServerJS,後來為了展現它的廣泛性,修改為CommonJS,平時我們也會簡稱為CJS。

Node是CommonJS在伺服器端一個具有代表性的實作;

  • Browserify是CommonJS在浏覽器中的一種實作;
  • webpack打包工具具備對CommonJS的支援和轉換;

是以,Node中對CommonJS進行了支援和實作,讓我們在開發node的過程中可以友善的進行子產品化開發:

  • 在Node中每一個js檔案都是一個單獨的子產品;
  • 這個子產品中包括CommonJS規範的核心變量:exports、module.exports、require;
  • 我們可以使用這些變量來友善的進行子產品化開發;

前面我們提到過子產品化的核心是導出和導入,Node中對其進行了實作:

  • exports和module.exports可以負責對子產品中的内容進行導出;
  • require函數可以幫助我們導入其他子產品(自定義子產品、系統子產品、第三方庫子產品)中的内容;
♣ 子產品化開發
♣ 子產品化開發

注意:exports是一個對象,我們可以在這個對象中添加很多個屬性,添加的屬性會導出;

♣ 子產品化開發

另外一個檔案中可以導入:

♣ 子產品化開發

上面這行完成了什麼操作呢?了解下面這句話,Node中的子產品化一目了然意味着main中的bar變量等于exports對象; 也就是require通過各種查找方式,最終找到了exports這個對象;并且将這個exports對象指派給了bar變量;bar變量就是exports對象了;

點選檢視代碼

const name = "why"
const age = 18
function sum(num1, num2) {
  return num1 + num2
}

// 源碼
// module.exports = {}
// exports = module.exports

// 第二種導出方式
// exports.name = name
// exports.age = age
// exports.sum = sum

// 這種代碼不會進行導出
// exports = {
//   name,
//   age,
//   sum
// }

// 這種代碼不會進行導出
// exports.name = name
// exports.age = age
// exports.sum = sum

module.exports = {

}

// 最終能導出的一定是module.exports           
♣ 子產品化開發

commonjs規範都是exports導出,但是Node中我們經常導出東西的時候,又是通過module.exports導出的, module.exports和exports有什麼關系或者差別呢?我們追根溯源,通過維基百科中對CommonJS規範的解析:

繼續閱讀