前端模組規格有三種:CommonJs,AMD和CMD。
CommonJs用在伺服器端,AMD和CMD用在瀏覽器環境。
AMD 是 RequireJS 在推廣過程中對模組定義的規範化產出。
CMD 是 SeaJS 在推廣過程中對模組定義的規範化產出。
AMD:提前執行(非同步載入:依賴先執行)+延遲執行
CMD:延遲執行(運行到需加載,根據順序執行)
函數寫法
function f1(){ //... } function f2(){ //... }
模組就是實作特定功能的文件,把幾個函數放在一個檔案裡就構成了一個模組。需要的時候載入這個文件,呼叫其中的函數即可。
但這樣做會污染全域變數,無法保證不與其他模組發生變數名稱衝突,而且模組成員之間沒什麼關係。
物件寫法
var module = { star : 0, f1 : function (){ //... }, f2 : function (){ //... } }; module.f1(); module.star = 1;
模組寫成一個對象,模組成員都封裝在物件裡,透過呼叫物件屬性,存取使用模組成員。但同時也暴露了模組成員,外部可以修改模組內部狀態。
立即執行函數
var module = (function(){ var star = 0; var f1 = function (){ console.log('ok'); }; var f2 = function (){ //... }; return { f1:f1, f2:f2 }; })(); module.f1(); //ok console.log(module.star) //undefined
外部無法存取內部私有變數
CommonJS是伺服器端模組的規範,由Node推廣使用。由於服務端程式設計的複雜性,如果沒有模組很難與作業系統及其他應用程式互動。使用方法如下:
math.js exports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) { sum += args[i++]; } return sum; }; increment.js var add = require('math').add; exports.increment = function(val) { return add(val, 1); }; index.js var increment = require('increment').increment; var a = increment(1); //2
根據CommonJS規格:
一個單獨的檔案就是一個模組。每一個模組都是一個單獨的作用域,也就是說,在該模組內部定義的變量,無法被其他模組讀取,除非定義為global物件的屬性。
輸出模組變數的最佳方法是使用module.exports物件。
載入模組使用require方法,該方法讀取一個檔案並執行,返回檔案內部的module.exports物件
仔細看上面的程式碼,您會注意到require 是同步的。模組系統需要同步讀取模組檔案內容,並編譯執行以獲得模組介面。
然而, 這在瀏覽器端問題多多。
瀏覽器端,載入 JavaScript 最佳、最容易的方式是在 document 中插入3f1c4e4b6b16bbbd69b2ee476dc4f83a標籤。但腳本標籤天生非同步,傳統 CommonJS 模組在瀏覽器環境中無法正常載入。
解決想法之一是,開發一個伺服器端元件,對模組程式碼進行靜態分析,將模組與它的依賴清單一起傳回給瀏覽器端。 這很好使,但需要伺服器安裝額外的元件,並因此要調整一系列底層架構。
另一種解決思路是,用一套標準模板來封裝模組定義:
define(function(require, exports, module) { // The module code goes here });
這套模板代碼為模組加載器提供了機會,使其能在模組代碼執行之前,對模組程式碼進行靜態分析,並動態產生依賴列表。
math.js define(function(require, exports, module) { exports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) { sum += args[i++]; } return sum; }; }); increment.js define(function(require, exports, module) { var add = require('math').add; exports.increment = function(val) { return add(val, 1); }; }); index.js define(function(require, exports, module) { var inc = require('increment').increment; inc(1); // 2 });
AMD是"Asynchronous Module Definition"的縮寫,意思是"非同步模組定義"。由於不是JavaScript原生支持,使用AMD規範進行頁面開發需要用到對應的庫函數,也就是大名鼎鼎RequireJS,實際上AMD 是RequireJS 在推廣過程中對模組定義的規範化的產出
# 它採用非同步方式載入模組,模組的載入不影響它後面語句的運作。所有依賴這個模組的語句,都定義在一個回呼函數中,等到載入完成之後,這個回調函數才會運行。
RequireJS主要解決兩個問題
#多個js檔案可能有依賴關係,被依賴的檔案需要早於依賴它的檔案載入到瀏覽器
js載入的時候瀏覽器會停止頁面渲染,載入檔案越多,頁面失去回應時間越長
RequireJs也採用require()語句載入模組,但是不同於CommonJS,它要求兩個參數:
第一個參數[module],是一個陣列,裡面的成員就是要載入的模組;第二個參數callback,則是載入成功之後的回呼函數。 math.add()與math模組載入不是同步的,瀏覽器不會發生假死。
require([module], callback); require([increment'], function (increment) { increment.add(1); });
define()函數
#RequireJS定义了一个函数 define,它是全局变量,用来定义模块:
define(id?, dependencies?, factory);
参数说明:
id:指定义中模块的名字,可选;如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了该参数,模块名必须是“顶级”的和绝对的(不允许相对名字)。
依赖dependencies:是一个当前模块依赖的,已被模块定义的模块标识的数组字面量。
依赖参数是可选的,如果忽略此参数,它应该默认为["require", "exports", "module"]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法。
工厂方法factory,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
来举个例子看看:
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //Or: return require("beta").verb(); } });
RequireJs使用例子
require.config是用来定义别名的,在paths属性下配置别名。然后通过requirejs(参数一,参数二);参数一是数组,传入我们需要引用的模块名,第二个参数是个回调函数,回调函数传入一个变量,代替刚才所引入的模块。
main.js //别名配置 requirejs.config({ paths: { jquery: 'jquery.min' //可以省略.js } }); //引入模块,用变量$表示jquery模块 requirejs(['jquery'], function ($) { $('body').css('background-color','red'); });
引入模块也可以只写require()。requirejs通过define()定义模块,定义的参数上同。在此模块内的方法和变量外部是无法访问的,只有通过return返回才行.
math.js define('math',['jquery'], function ($) {//引入jQuery模块 return { add: function(x,y){ return x + y; } }; });
将该模块命名为math.js保存。
require(['jquery','math'], function ($,math) { console.log(math.add(10,100));//110 });
main.js引入模块方法
CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,就像AMD有个requireJS,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同。
在 CMD 规范中,一个模块就是一个文件。代码的书写格式如下:
define(function(require, exports, module) { // 模块代码 });
require是可以把其他模块导入进来的一个参数;而exports是可以把模块内的一些属性和方法导出的;module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。
AMD是依赖关系前置,在定义模块的时候就要声明其依赖的模块;
CMD是按需加载依赖就近,只有在用到某个模块的时候再去require:
// CMD define(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... }) // AMD 默认推荐的是 define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() ... })
seajs使用例子
// 定义模块 myModule.js define(function(require, exports, module) { var $ = require('jquery.js') $('p').addClass('active'); exports.data = 1; }); // 加载模块 seajs.use(['myModule.js'], function(my){ var star= my.data; console.log(star); //1 });
以上是理解前端模組化(CommonJs,AMD和CMD)的詳細內容。更多資訊請關注PHP中文網其他相關文章!