Javarscript中模塊(module)、加載(load)與捆綁(bundle)詳解
JS模塊簡(jiǎn)介
js模塊化,簡(jiǎn)單說就是將系統(tǒng)或者功能分隔成單獨(dú)的、互不影響的代碼片段,經(jīng)過嚴(yán)格定義接口,使各模塊間互不影響,且可以為其他所用。
常見的模塊化有,C中的include (.h)文件、java中的import等。
為什么JS需要模塊
很顯然,沒有模塊我們也可以實(shí)現(xiàn)同樣的功能,為什么我們還要使用模塊來寫js代碼呢?下面幾點(diǎn)是模塊化給我們帶來的一些變化:
- 抽象代碼:我們?cè)谑褂媚K來調(diào)用一個(gè)api時(shí),可以不用知道內(nèi)部是如何實(shí)現(xiàn)的,避免去理解其中復(fù)雜的代碼;
- 封裝代碼:在不需要再次修改代碼的前提下,我們可以在模塊內(nèi)部隱藏其具體實(shí)現(xiàn);
- 復(fù)用代碼:一些常用的、通用的功能,以模塊來實(shí)現(xiàn)可以避免過多的重復(fù)代碼;
- 管理依賴:可以通過簡(jiǎn)單的修改依賴項(xiàng)來管理功能的實(shí)現(xiàn),而不需要去重新修改自己內(nèi)部的代碼實(shí)現(xiàn)。
- …
ES5及之前的模塊系統(tǒng)
在ES5及之前版本,還沒有原生的模塊語法。不過這并不代表ES5之前,前端沒有使用模塊。簡(jiǎn)單介紹兩種:IIFE、Revealing Module.
IIFE
Immediately Invoked Function Expression,立即執(zhí)行函數(shù)表達(dá)式。
(function(){
// ...
})()
看上面的代碼,IIFE可以說成是一個(gè)在定義的時(shí)候就執(zhí)行的匿名函數(shù)。注意函數(shù)是先被”()”包起來了,然后后面緊跟”()”表示執(zhí)行函數(shù)。如果是以下代碼,將會(huì)報(bào)錯(cuò):
function(){
console.log('test');
}()
// => Uncaught SyntaxError: Unexpected token )
這種寫法表示,先定義一個(gè)匿名函數(shù),然后再去解析”()”。由于在第一行”function”出現(xiàn)在首位,這表明此處定義一個(gè)函數(shù),函數(shù)后緊跟”()”,此時(shí)表示單獨(dú)解析”()”,就會(huì)報(bào)出上面的錯(cuò)誤信息,因此需要先將函數(shù)定義包裹起來。
“(function…)”這種寫法表示執(zhí)行”()”內(nèi)部代碼,并返回該語句執(zhí)行結(jié)果,此處返回結(jié)果為該函數(shù),后面緊跟”()”即表示執(zhí)行該函數(shù)。IIFE可以幫助我們做到:
- 不需要了解具體的代碼實(shí)現(xiàn)情況下取得想要的效果;
- 在內(nèi)部定義的變量不會(huì)污染全局作用域。
顯而易見,這種編碼方式并沒有提供良好的機(jī)制來解決依賴管理問題。
Revealing Module
根據(jù)字面暫解釋為揭示模式,與IIFE形式類似,但是提供了一個(gè)返回值。方便集中管理公有的api,使模塊、公用api更加簡(jiǎn)潔清晰。
// Expose module as global variable
var singleton = function(){
// Inner logic
function sayHello(){
console.log('Hello');
}
// Expose API
return {
sayHello: sayHello
}
}()
稍微注意下,上面的代碼,我們并沒有用”()”去包裹,因?yàn)殛P(guān)鍵字”function”并不在該行的開頭。
我們可以像下面這樣使用模塊api:
// Access module functionality singleton.sayHello(); // => Hello
當(dāng)然,我們也可以以構(gòu)造函數(shù)形式導(dǎo)出:
// Expose module as global variable
var Module = function(){
// Inner logic
function sayHello(){
console.log('Hello');
}
// Expose API
return {
sayHello: sayHello
}
}
請(qǐng)注意,上面函數(shù)在定義的時(shí)候并沒有執(zhí)行。
我們可以這么使用它:
var module = new Module(); module.sayHello(); // => Hello
與IIFE一樣,揭示模式并沒有提供良好的解決依賴管理的方案。
更多模塊化解決方案
ES6或者ES2015,自帶原生的模塊語法。
在這之前,有以下幾種常見的用于模塊化的解決方案:
- AMD
- CMD
- CommonJs
- UMD
- System.register
- ES6
AMD
AMD,Asynchronous Module Definition,異步模塊定義。AMD形式被用于瀏覽器端,使用”define”來定義模塊依賴:
//Calling define with a dependency array and a factory function
define(['dep1', 'dep2'], function (dep1, dep2) {
//Define the module value by returning a value.
return function () {};
});
CMD
CMD,Common Module Definition,通用模塊定義。該規(guī)范由國內(nèi)大神玉伯提出,與AMD區(qū)別在與AMD是依賴關(guān)系前置,有該依賴就必須先加載依賴,CMD是按需加載。
// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此處略去 100 行
var b = require('./b') // 依賴可以就近書寫
b.doSomething()
// ...
})
// AMD 默認(rèn)推薦的是
define(['./a', './b'], function(a, b) { // 依賴必須一開始就寫好
a.doSomething()
// 此處略去 100 行
b.doSomething()
...
})
CommonJs
CommonJs在Node.js中用的較多,使用”require”來定義依賴,使用”module.exports”來定義模塊:
var dep1 = require('./dep1');
var dep2 = require('./dep2');
module.exports = function(){
// ...
}
UMD
UMD,Universal Module Definition,通用模塊定義??梢杂糜跒g覽器端與Node.js端:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['b'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(require('b'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.b);
}
}(this, function (b) {
//use b in some fashion.
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
return {};
}));
System.register
System.register方式設(shè)計(jì)初衷主要是為了在ES5中能夠支持ES6模塊語法:
import { p as q } from './dep';
var s = 'local';
export function func() {
return q;
}
export class C {
}
ES6 module
ES6中自帶原生的模塊語法,使用關(guān)鍵字”export”來導(dǎo)出模塊的公用api:
// lib.js
// Export the function
export function sayHello(){
console.log('Hello');
}
// Do not export the function
function somePrivateFunction(){
// ...
}
以關(guān)鍵字”import”來導(dǎo)入模塊:
import { sayHello } from './lib';
sayHello();
// => Hello
目前各瀏覽器對(duì)ES6的支持度不一,因此我們現(xiàn)在需要使用編譯器,像Babel,來將ES6的代碼編譯成ES5的形式。
模塊加載器
一個(gè)模塊加載器可以理解模塊,并以固定的形式來加載模塊。
模塊加載器工作在運(yùn)行時(shí),流程大致如下:
- 你在瀏覽器中運(yùn)行模塊加載器;
- 你告訴模塊加載器需要加載哪個(gè)主文件;
- 模塊加載器下載并解析主文件;
- 模塊加載器按需加載其他文件。
一些比較常見的模塊加載器有:
- RequireJS:以AMD風(fēng)格加載模塊;
- SeaJS:以CMD風(fēng)格加載模塊;
- SystemJS:以AMD, CommonJS, UMD 或者 System.register風(fēng)格加載模塊;
- jspm:jspm基于SystemJS,是模塊加載器,同時(shí)也具備瀏覽器端包管理功能。
模塊打包
模塊打包可以替換模塊加載器。
然而,相比模塊加載器,模塊打包動(dòng)作是在編譯時(shí)運(yùn)行的:
- 使用模塊打包在編譯期生成一個(gè)js文件;(例如bundle.js)
- 在瀏覽器中加載該文件。
截止目前,比較常用的模塊打包方案有以下兩種:
- Browserify:為CommonJS模塊打包;
- Webpack: 為AMD、CommonJS、ES6模塊打包。
總結(jié)
為了在現(xiàn)代js開發(fā)環(huán)境中更好的使用這些工具,你首先需要知道模塊、模塊化解決方案、模塊加載、模塊打包之前的區(qū)別。
模塊是一段封裝好的代碼,可以以公用api形式導(dǎo)出并在其他代碼中被加載和調(diào)用;
模塊化解決方案或者模塊化思想,實(shí)際含義是定義一個(gè)模塊的語法。由于定義語法的差異,目前常用的有AMD、CMD、CommonJS、UMD等;
模塊加載,在運(yùn)行期解析和加載模塊。常見的有RequireJS、SeaJS、SystemJS和jspm;
模塊打包,其替換了模塊加載的概念,在編譯期間生成一個(gè)所有代碼整合后的bundle.js文件。常見的有Browserify和Webpack。
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家腳本之家的支持。
相關(guān)文章
webpack配置文件外置的兩種實(shí)現(xiàn)方式
webpack配置環(huán)境變量文件,是根據(jù)打包命令尋找對(duì)應(yīng)的環(huán)境變量文件,從而獲取接口地址,本文就來介紹一下webpack配置文件外置的兩種實(shí)現(xiàn)方式,感興趣的可以了解一下2023-12-12
深入理解JavaScript繼承的多種方式和優(yōu)缺點(diǎn)
這篇文章主要介紹了深入理解JavaScript繼承的多種方式和優(yōu)缺點(diǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
淺談一個(gè)webpack構(gòu)建速度優(yōu)化誤區(qū)
這篇文章主要介紹了淺談一個(gè)webpack構(gòu)建速度優(yōu)化誤區(qū),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-06-06
JS使用iView的Dropdown實(shí)現(xiàn)一個(gè)右鍵菜單
這篇文章主要介紹了JS使用iView的Dropdown實(shí)現(xiàn)一個(gè)右鍵菜單功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05
javascript實(shí)現(xiàn)div浮動(dòng)在網(wǎng)頁最頂上并帶關(guān)閉按鈕效果實(shí)例
我們有時(shí)會(huì)看到有些網(wǎng)站最頂部一直會(huì)跟著我們滾動(dòng)而滾動(dòng)了,這種方法其實(shí)很簡(jiǎn)單,下面我來給大推薦一個(gè)javascript實(shí)現(xiàn)div浮動(dòng)在網(wǎng)頁最頂上并帶關(guān)閉按鈕效果2013-08-08

