前端開發之模塊化開發中的規範講解--commonjs、AMD、CMD、ES6

commonjs、AMD、CMD、ES6有什麼區別?是什麼意思?前端開發爲何要模塊化?由於聽朋友說面試時被問道,不是很清楚,因此想在此闡述一下。

複製代碼

一、爲何前端使用模塊化開發?

       模塊化是指把一個複雜的系統分解到多個模塊以方便編碼。就像積木,咱們能夠能夠重複的利用這些積木組成不一樣的形狀。一個模塊就是實現特定功能的文件,有了模塊,咱們就能夠更方便地使用別人的代碼,想要什麼功能,就加載什麼模塊。模塊開發須要遵循必定的規範,不然就都亂套了。javascript

二、commonjs、AMD、CMD、ES6是什麼?

commonjs、AMD、CMD是一種規範也是一種標準。

  2.1 AMD

AMD 是RequireJs在推廣過程當中對模塊化定義的規範化產出。(異步模塊)AMD 規範主要是爲了解決針對 瀏覽器環境的模塊化問題。

AMD異步加載模塊。它的模塊支持對象 函數 構造器 字符串 JSON等各類類型的模塊。 
前端

AMD 的優勢java

  • 可在不轉換代碼的狀況下直接在瀏覽器中運行
  • 可加載多個依賴
  • 代碼可運行在瀏覽器環境和 Node.js 環境下

AMD 的缺點node

  • JavaScript 運行環境沒有原生支持 AMD,須要先導入實現了 AMD 的庫後才能正常使用。

  用法:jquery

// 定義模塊,三個參數
define(id?, deps?, factory)

// 執行模塊,兩個參數 依賴前置
require(deps, factory)
複製代碼

例子:
// 定義一個模塊  經過數組引入依賴 ,回調函數經過形參傳入依賴 
define('a', [], function () {
    return 'a';
});
define('b', ['a'], function (a) {
    return a + 'b';
});
// 導入和使用
require(['b'], function (b) {
    console.log(b);
});
複製代碼

例子分析:nginx

參數說明:git

id:指定義中模塊的名字,可選;若是沒有提供該參數,模塊的名字應該默認爲模塊加載器請求的指定腳本的
名字。若是提供了該參數,模塊名必須是「頂級」的和絕對的(不容許相對名字)。

依賴deps:是一個當前模塊依賴的,已被模塊定義的模塊標識的數組字面量。
依賴參數是可選的,若是忽略此參數,它應該默認爲["require", "exports", "module"]。
然而,若是工廠方法的長度屬性小於3,加載器會選擇以函數的長度屬性指定的參數個數調用工廠方法。

工廠方法factory,模塊初始化要執行的函數或對象。若是爲函數,它應該只被執行一次。
若是是對象,此對象應該爲模塊的輸出值。複製代碼

經過define來定義一個模塊,a 和 b,由於require用到了b,全部須要依賴前置,先定義b,而b中又用到了aes6

經過deps參數,很容易知道該文件依賴的腳本是b.js,而後去加載依賴的腳本,加載完以後執行一遍而且將執行的結果做爲回調函數factory的參數,而後執行該匿名的回調函數便可。github

ps:面試

require API 介紹:github.com/amdjs/amdjs…

AMD規範中文版:github.com/amdjs/amdjs…

原理:

let factories = {};
function define(modName, dependencies, factory) {
    factory.dependencies = dependencies;
    factories[modName] = factory;
}
function require(modNames, callback) {
    let loadedModNames = modNames.map(function (modName) {
        let factory = factories[modName];
        let dependencies = factory.dependencies;
        let exports;
        require(dependencies, function (...dependencyMods) {
            exports = factory.apply(null, dependencyMods);
        });
        return exports;
    })
    callback.apply(null, loadedModNames);
}
複製代碼

2.2 cmd

CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出。該規範明確了模塊的基本書寫格式和基本交
互規則。該規範是在國內(淘寶)發展出來的。同步概念。複製代碼

在 CMD 規範中,一個模塊就是一個文件。

代碼的書寫格式以下:

define(factory);複製代碼

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

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

factory 爲對象、字符串時,表示模塊的接口就是該對象、字符串。好比能夠以下定義一個 JSON 數據模塊:

define({ "foo": "bar" });複製代碼

也能夠經過字符串定義模板模塊:

define('I am a template. My name is {{name}}.');複製代碼

factory 爲函數時,表示是模塊的構造方法。執行該構造方法,能夠獲得模塊向外提供的接口。factory 方法在執行時,默認會傳入三個參數:requireexportsmodule

define(function(require, exports, module) {

  // 模塊代碼

});複製代碼

define define(id?, deps?, factory)

define 也能夠接受兩個以上參數。字符串 id 表示模塊標識,數組 deps 是模塊依賴。好比:

define('hello', ['jquery'], function(require, exports, module) {

  // 模塊代碼

});複製代碼

iddeps 參數能夠省略。省略時,能夠經過構建工具自動生成。

注意:帶 iddeps 參數的 define 用法不屬於 CMD 規範,而屬於 Modules/Transport 規範。

CMD具體規範: github.com/seajs/seajs…

sea.js如何使用?

  • 1.- 引入sea.js的庫
  •  2.- 如何變成模塊? - define - 
  • 3.-如何調用模塊?  -exports -sea.js.use 
  • 4.-如何依賴模塊? -require
<script type="text/javascript"> define(function (require,exports,module) { //exports : 對外的接口 //requires : 依賴的接口 require('./test.js');//若是地址是一個模塊的話,那麼require的返回值就是模塊中的exports }) </script> 複製代碼

2.3 commonjs

CommonJS是服務器端模塊的規範,Node.js採用了這個規範。Node.JS首先採用了js模塊化的概念。核心思想是經過
require方法來同步地加載依賴的其餘模塊,經過 module.exports 導出須要暴露的接口。複製代碼

一、根據CommonJS規範,一個單獨的文件就是一個模塊。

二、每個模塊都是一個單獨的做用域,也就是說,在該模塊內部定義的變量,沒法被其餘模塊讀取,除非定義爲global對象的屬性。

三、模塊能夠屢次加載,但只會在第一次加載的時候運行一次,而後運行結果就被緩存了,之後再加載,就直接讀取緩存結果;模塊的加載順序,按照代碼的出現順序是同步加載的;

四、__dirname表明當前模塊文件所在的文件夾路徑,__filename表明當前模塊文件所在的文件夾路徑+文件名;

五、require(同步加載)基本功能:讀取並執行一個JS文件,而後返回該模塊的exports對象,若是沒有發現指定模塊會報錯;

六、模塊內的exports:爲了方便,node爲每一個模塊提供一個exports變量,其指向module.exports,至關於在模塊頭部加了這句話:var exports = module.exports,在對外輸出時,能夠給exports對象添加方法,PS:不能直接賦值(由於這樣就切斷了exports和module.exports的聯繫);

七、npm root -g:查看npm全局包安裝位置,建議在nvm目錄下新建npm\node_modules目錄,而後設置npm的全局包安裝位置:npm config set prefix "",而後將該路徑添加到環境變量中;

八、npm init -y:初始化一個package.json文件,加上-y就會默認生成該文件,無需一步一步填寫;npm docs 包名:查看包的文檔;npm install:安裝package.json中dependencies屬性中全部依賴的包

九、因爲npm的服務器是國外的,因此若是你沒有和諧工具是下載不了的,這裏推薦使用淘寶NPM鏡像:http://npm.taobao.org/,與官方NPM的同步頻率目前爲10分鐘一次;安裝命令:npm install -g cnpm --registry=https://registry.npm.taobao.org,安裝包:cnpm install 包名(其它命令基本一致);

十、若是你不想下載cnpm,npm還提供了一個鏡像源管理工具:npm install -g nrm,經過:nrm ls,查看鏡像源列表 ,經過:npm use 鏡像源,來切換;

十一、NPM的模塊加載機制:

若是require的是絕對路徑文件,查找不會去遍歷每一個node_modules目錄,其速度最快

  1).從module.paths數組中(由當前執行文件目錄到磁盤根目錄)取出第一個目錄做爲查找基準

  2).直接從目錄中查找該文件,若是存在則結束查找,若是不存在則進行下一條查找

  3).嘗試添加.js、.node、.json後綴以後查找,若是存在文件則結束查找,若是不存在則進行下一條查找

  4).嘗試將require的參數做爲一個包來進行查找,讀取目錄下的package.json文件,取得Main參數指定的文件

  5).嘗試查找該文件,若是存在則結束查找,若是不存在則進行第3條查找

  6).若是繼續失敗,則取出module.paths數組中的下一目錄做爲基準查找,循環第1-5個步驟

  7).若是繼續失敗,循環第1-6個步驟,直到module.paths中的最後一個值

  8).若是繼續失敗,則拋出異常


CommonJS定義的模塊分爲:

{模塊引用(require)} {模塊定義(exports)} {模塊標識(module)}

require()用來引入外部模塊;

exports對象用於導出當前模塊的方法或變量,惟一的導出口;module對象就表明模塊自己。

用法

採用 CommonJS 導入及導出時的代碼以下:

// 導入
const someFun= require('./moduleA');
someFun();

// 導出
module.exports = someFunc;複製代碼


 原理

a.js

let fs = require('fs');
let path = require('path');
let b = req('./b.js');
function req(mod) {
    let filename = path.join(__dirname, mod);
    let content = fs.readFileSync(filename, 'utf8');
    let fn = new Function('exports', 'require', 'module', '__filename', '__dirname', content + '\n return module.exports;');
    let module = {
        exports: {}
    };

    return fn(module.exports, req, module, __filename, __dirname);
}
複製代碼

b.js

console.log('bbb');
exports.name = 'Jones';複製代碼

2.4 ES6 模塊化

ES6 模塊化是ECMA提出的JavaScript模塊化規範,它在語言的層面上實現了模塊化。瀏覽器廠商和Node.js 都宣佈要原生支持該規範。它將逐漸取代CommonJSAMD`規範,成爲瀏覽器和服務器通用的模塊解決方案。 採用 ES6 模塊化導入及導出時的代碼以下

// 導入
import { name } from './person.js';
// 導出
export const name = 'Jones';複製代碼

三、區別

commonJS規範:服務端的模塊化規範,不適用於瀏覽器環境。適用於nodejs,終極目標是提供一個相似Python,Ruby和Java標準庫。

AMD、CMD;瀏覽器端模塊化開發的規範,都是模塊加載器,倡導模塊化開發理念,核心價值是讓 JavaScript 的模塊化開發變得簡單天然。區別:CMD對模塊的態度是懶執行(同步), 而AMD對模塊的態度是預執行(異步)ps:AMD目前也在同步。

commonjs\AMD、CMD是es5中退出的。

es6中的:import|export 


本文內容參考網上內容,若有雷同和錯誤,請與我聯繫。

相關文章
相關標籤/搜索