先列舉下一些著名言論:前端
「我想定義一個 each 方法遍歷對象,但頁頭的 util.js 裏已經定義了一個,個人只能叫 eachObject 了,好無奈。」jquery
「RequireJS 是沒有明顯的 bug,SeaJS 是明顯沒有 bug。」git
「在用SeaJS,除了打包很是痛苦外,其餘的還好」程序員
「你變了精彩的魔術,咱們會爲你喝彩。但你想讓咱們信任你,你得主動解釋魔術的奧祕。不然我會以爲本身被耍了。」github
「這兩個加載器和標準沒有優劣之分,只有差異。具體仍是要根據實際狀況進行選擇;」正則表達式
……npm
這個是個老掉牙的話題,我就再也不誤人子弟了,歡迎閱讀這篇由 玉伯 大大執筆的《 前端模塊化開發的價值 》api
模塊的版本管理 。經過別名等配置,配合構建工具,能夠比較輕鬆地實現模塊的版本管理。瀏覽器
提升可維護性 。模塊化可讓每一個文件的職責單一,很是有利於代碼的維護。Sea.js 還提供了 nocache、debug 等插件,擁有在線調試等功能,能比較明顯地提高效率。性能優化
前端性能優化 。Sea.js 經過異步加載模塊,這對頁面性能很是有益。Sea.js 還提供了 combo、flush 等插件,配合服務端,能夠很好地對頁面性能進行調優。
跨環境共享模塊 。CMD 模塊定義規範與 Node.js 的模塊規範很是相近。經過 Sea.js 的 Node.js 版本,能夠很方便實現模塊的跨服務器和瀏覽器共享。
sea.js是一個專門爲解決瀏覽器模塊化開發的方案,SeaJS定義了一個全局函數 define 它用來定義一個模塊,SeaJS提倡:文件即模塊。
全部模塊都經過 define 來定義
define(function(require, exports, module) { // 經過 require 引入依賴 注意 .js 能夠省略 var $ = require('jquery'); // 你也能夠引入本身的函數依賴 var Spinning = require('./yourFunction'); var util = {}; util.sayHello = function(){ return 'seajs向你問好'; } // 經過 exports 對外提供接口 // exports 和 module.exports 區別見下文: //exports.doSomething = function() { //}; // 或者經過 module.exports 提供整個接口 module.exports = util; }); // 看完這一段 你應該明白了 require, exports, module 三個參數
既然是 回顧 那就應該好文不斷: 《 前端模塊化開發那點歷史 》
簡單說: 就是 異步模塊定義(Asynchronous Module Definition),它是 依賴前置 (由於依賴必須一開始就寫好)會先 儘早地執行(依賴)模塊 , 至關於全部的require都被提早了,它的 require 分全局和局部, 一個API當多個用 。
define() 函數
看下它的具體參數說明
define( //這個模塊的名稱 "types/Manager", //依賴的模塊 ["types/Employee"], //函數執行時,全部依賴項加載。這個函數的參數依賴上述模塊。 function (Employee) { function Manager () { this.reports = []; } //開始執行 Manager.prototype = new Employee(); //返回經理構造函數能夠由其餘模塊的應用。 return Manager; } );
建立一個名爲"alpha"的模塊,使用了require,exports,和名爲"beta"的模塊:
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //或者: //return require("beta").verb(); } });
一個返回對象的匿名模塊:
define(["alpha"], function (alpha) { return { verb: function(){ return alpha.verb() + 2; } }; });
一個使用了簡單CommonJS轉換的模塊定義:
define(function (require, exports, module) { var a = require('a'), b = require('b'); exports.action = function () {}; });
中文版在這裏 : CMD 模塊定義規範 ,也有 鳥語版
簡單說 : CMD(Common Module Definition)更貼近 CommonJS Modules/1.1 和 Node Modules 規範,一個模塊就是一個文件;它推崇 依賴就近 想何時 require 就何時加載,實現了 懶加載, 延遲執行 (as lazy as possible) ;也沒有全局 require, 每一個API都簡單純粹 。
define() 函數相似,看定義便可
常用的 API 只有 define, require, require.async, exports, module.exports 這五個。其餘 API 有個印象就好。
傳給 factory 構造方法的 exports 參數是 module.exports 對象的一個引用。只經過 exports 參數來提供接口,有時沒法知足開發者的全部需求。 好比當模塊的接口是某個類的實例時,須要經過 module.exports 來實現:
define(function(require, exports, module) { // exports 是 module.exports 的一個引用 console.log(module.exports === exports); // true // 從新給 module.exports 賦值 module.exports = new SomeClass(); // exports 再也不等於 module.exports console.log(module.exports === exports); // false });
對 module.exports 的賦值須要同步執行,不能放在回調函數裏。下面這樣是不行的:
// x.js define(function(require, exports, module) { // 錯誤用法 setTimeout(function() { module.exports = { a: "hello" }; }, 0); });
在 y.js 裏有調用到上面的 x.js:
// y.js define(function(require, exports, module) { var x = require('./x'); // 沒法馬上獲得模塊 x 的屬性 a console.log(x.a); // undefined });
當咱們看到RequireJS 的接口,
require(['a','b'],function(){ //Do something })
實際作的事情是:
一、require 函數檢查依賴的模塊,根據配置文件,獲取js文件的實際路徑
二、根據js文件實際路徑,在dom中插入script節點,並綁定onload事件來獲取該模塊加載完成的通知。
三、依賴script所有加載完成後,調用回調函數
Sea.js在調用時 :
define('a',function(require,exports,modules){ var b = require('b') })
一、經過回調函數的Function.toString函數,使用正則表達式來捕捉內部的require字段,找到require('jquery')內部依賴的模塊jquery
二、根據配置文件,找到jquery的js文件的實際路徑
三、在dom中插入script標籤,載入模塊指定的js,綁定加載完成的事件,使得加載完成後將js文件綁定到require模塊指定的id(這裏就是jquery這個字符串)上
四、回調函數內部依賴的js所有加載(暫不調用)完後,調用回調函數
五、當回調函數調用require('jquery'),即執行綁定在'jquery'這個id上的js文件,即刻執行,並將返回值傳給var b
注意: SeaJS 這種用 ** 正則表達式 捕捉require內部依賴模塊的方式** ,使得沒法利用還沒有執行的回調函數中的js運行環境,致使require函數的內部只能將依賴的模塊名稱硬編碼,就不能寫下面這樣的代碼了
define('a',function(require,exports,modules){ //錯誤 var b = require('Us'+'er'); })
而只能寫成
define('a',function(require,exports,modules){ //正確 var b = require('User'); })
其餘的區別其實介紹時已經說明了,上文~ 小總結:玉伯:與 RequireJS 的異同
RequireJS 和 Sea.js 都是模塊加載器,倡導模塊化開發理念,核心價值是讓 JavaScript 的模塊化開發變得簡單天然。
二者的主要區別以下:
定位有差別。RequireJS 想成爲瀏覽器端的模塊加載器,同時也想成爲 Rhino / Node 等環境的模塊加載器。Sea.js 則專一於 Web 瀏覽器端,同時經過 Node 擴展的方式能夠很方便跑在 Node 環境中。
遵循的規範不一樣。RequireJS 遵循 AMD(異步模塊定義)規範,Sea.js 遵循 CMD (通用模塊定義)規範。規範的不一樣,致使了二者 API 不一樣。Sea.js 更貼近 CommonJS Modules/1.1 和 Node Modules 規範。
推廣理念有差別。RequireJS 在嘗試讓第三方類庫修改自身來支持 RequireJS,目前只有少數社區採納。Sea.js 不強推,採用自主封裝的方式來「海納百川」,目前已有較成熟的封裝策略。
對開發調試的支持有差別。Sea.js 很是關注代碼的開發調試,有 nocache、debug 等用於調試的插件。RequireJS 無這方面的明顯支持。
二者代碼質量有差別。RequireJS 是沒有明顯的 bug,SeaJS 是明顯沒有 bug。
插件機制不一樣。RequireJS 採起的是在源碼中預留接口的形式,插件類型比較單一。Sea.js 採起的是通用事件機制,插件類型更豐富。
還有很多差別,涉及具體使用方式和源碼實現,歡迎有興趣者研究並發表見解。
總之,若是說 RequireJS 是 Prototype 類庫的話,則 Sea.js 致力於成爲 jQuery 類庫。
這裏有一個圖文並茂的 「栗子」 SeaJS與RequireJS最大的區別,固然樓主的觀點更同意這個「栗子」: LABjs、RequireJS、SeaJS 哪一個最好用?爲何?
結論: 這兩個加載器和標準沒有優劣之分,只有差異。具體仍是要根據實際狀況進行選擇;
完