您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關js中常用模塊化方案有哪些的內容。小編覺得挺實用的,因此分享給大家做個參考。一起跟隨小編過來看看吧。
本篇文章給大家帶來的內容是關于為什么需要模塊化?js中常用模塊化方案介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
為什么需要模塊化
在ES6出現之前,JS語言本身并沒有提供模塊化能力,這為開發帶來了一些問題,其中最重要的兩個問題應當是全局污染和依賴管理混亂。
// file a.js var name = 'aaa'; var sayName = function() { console.log(name); };
<!-- file index.html --> <script src='xxx/xxx/a.js'></script> <script> sayName(); // 'aaa' // code... var name = 'bbb'; sayName(); // 'bbb' </script>
上面的代碼中,我們兩次調用a.js所提供的sayName函數輸出了不同結果,很明顯這是因為兩個文件都對變量name進行了賦值,因此相互之間造成了影響。當然我們可以在編寫代碼時注意不要定義已存在的變量名,但是當一個頁面引用了10幾個幾百行的文件時,記住所有已經定義過的變量顯然不太現實。
// file a.js var name = getName(); var sayName = function() { console.log(name) };
// file b.js var getName = function() { return 'timo'; };
<script src='xxx/xxx/b.js'></script> <script src='xxx/xxx/a.js'></script> <script> sayName(); // 'timo' </script>
<script src='xxx/xxx/a.js'></script> <script src='xxx/xxx/b.js'></script> // Uncaught ReferenceError: getName is not defined
上面的代碼說明,多個文件有依賴關系時,我們需要確保其引入的順序,從而保證運行某個文件時,其依賴已經提前加載,可以想象,面對越大型的項目,我們需要處理的依賴關系也就越多,這既麻煩又容易出錯。
而為了解決這些,社區中出現了許多為JS語言提供模塊化能力的規范,借助這些規范,能讓我們的開發更加方便安全。
常見模塊化方案
CommonJS是由社區提出的模塊化方案中的一種,Node.js遵循了這套方案。
// file a.js var obj = { sayHi: function() { console.log('I am timo'); }; }; module.exports obj;
// file b.js var Obj = require('xxx/xxx/a.js'); Obj.sayHi(); // 'I am timo'
上面的代碼中,文件a.js是模塊的提供方,文件b.js是模塊調用方。
每個文件都是一個模塊;
在模塊內提供module對象,表示當前模塊;
模塊使用exports對外暴露自身的函數/對象/變量等;
模塊內通過require()方法導入其他模塊;
CommonJS的規范,簡單來說就是上面4條,可以對照基本寫法中的例子理解一下,在實際實現中,Node.js雖然遵循CommonJS規范,但是仍然對其進行了一些調整。
AMD是模塊化規范中的一種,RequireJS遵循了這套規范。
// file a.js define('module', ['m', './xxx/n.js'], function() { // code... })
上面的代碼中,文件a.js向外導出了模塊;
AMD中,暴露模塊使用define函數
define(moduleName, [], callback);
如上面代碼,define函數共有三個參數
moduleName該參數可以省略,表示該模塊的名字,一般作用不大
['name1', 'name2'],第二個參數是一個數組,表示當前模塊依賴的其他模塊,如果沒有依賴模塊,該參數可以省略
callback,第三個參數是必傳參數,是一個回調函數,內部是當前模塊的相關代碼
ADM的特點是依賴前置,這是ADM規范與接下來要介紹的CMD規范最大的不同,依賴前置是指:在運行當前加載模塊回調前,會首先將所有依賴包加載完畢,也是就是define函數的第二個參數中指定的依賴包。
define(function(require, exports, module) { var a = require('./a') a.doSomething(); // code... var b = require('./b') // code... })
上面代碼是CMD規范導出模塊的基本寫法;
從寫法可以看出,CMD的寫法和AMD非常像,其主要區別是對于依賴加載時機的不同,上面已經說過,AMD是依賴前置,而CMD規范推崇就近原則,簡單說就是在模塊運行前并不加載依賴,模塊運行過程中,當需要某個依賴時,再去進行加載。
CommonJS、AMD、CMD并行的狀態下,就需要一種方案能夠兼容他們,這樣我們在開發時,就不需要再去考慮依賴模塊所遵循的規范了,而UMD的出現就是為了解決這個問題。
(function (root, factory) { if (typeof define === 'function' && define.amd) { //AMD define(['jquery'], factory); } else if (typeof exports === 'object') { //Node, CommonJS之類的 module.exports = factory(require('jquery')); } else { //瀏覽器全局變量(root 即 window) root.returnExports = factory(root.jQuery); } }(this, function ($) { //方法 function myFunc(){}; //暴露公共方法 return myFunc; }));
上面的代碼是UMD的基本寫法,從代碼就可以看出,其能夠同時支持CommonJS規范和AMD規范。
上面分別介紹了CommonJS、AMD、CMD和UMD,他們都是社區對于JS實現模塊化的貢獻,這個規范其產生的根本原因,都是JS語言自身沒有模塊化能力,而目前,在JS最新的語言規范ES6中,已經為JS增加了模塊化能力,而JS自身的模塊化方案,完全能夠替代目前社區提出的各類規范,且能夠做到瀏覽器端和Node端通用。
ES6中的模塊化能力由兩個命令構成:export和import,export命令用于規定模塊的對外接口,import命令用于輸入其他模塊提供的功能。
ES6中一個文件就是一個模塊,模塊內部的變量/函數等外部是無法訪問的,如果希望將內部的函數/變量等對外暴露,供其他模塊進行使用,就需要通過export命令進行導出
// file a.js export let a = 1; export let b = 2; export let c = 3;
// file b.js let a = 1; let b = 2; let c = 3; export {a, b, c}
// file c.js export let add = (a, b) => { return a + b; };
上面三個文件的代碼,都是通過export命令導出模塊內容的示例,其中a.js文件和b.js文件都是導出模塊中的變量,作用完全一致但寫法不同,一般我們更推薦b.js文件中的寫法,原因是這種寫法能夠在文件最底部清楚地知道當前模塊都導出了哪些變量。
模塊通過export命令導出變量/函數等,是為了讓其他模塊能夠導入去使用,在ES6中,文件導入其他模塊是通過import命令進行的
// file d.js import {a, b, c} from './a.js';
上面的代碼中,我們引入了a.js文件中的變量a、b、c,import在引入其他模塊內的函數/變量時,必須與原模塊所暴露出來的函數名/變量名一一對應。
同時,import命令引入的值是只讀的,如果嘗試對其進行修改,則會報錯
import {a} d from './a.js'; a = 2; // Syntax Error : 'a' is read-only;
從上面import的介紹可以看到,當需要引入其他模塊時,需要知道此模塊暴露出的變量名/函數名才可以,這顯然有些麻煩,因此ES6還提供了一個import default命令
// file a.js let add = (a, b) => { return a+b }; export default add;
// file b.js import Add from './a.js'; Add(1, 2); // 3
上面的代碼中,a.js通過export default命令導出了add函數,在b.js文件中引入時,可以隨意指定其名稱
export default命令是默認導出的意思,既然是默認導出,顯然只能有一個,因此每個模塊只能執行一次export default命令,其本質是導出了一個名為default的變量或函數。
感謝各位的閱讀!關于js中常用模塊化方案有哪些就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。