模塊化出現以前,實現模塊化的一種方法是使用當即執行函數(IIFE),在 window
上添加屬性javascript
window
添加屬性JS:css
// index.js (function(window) { // window 是全局變量,可缺省 let str = 'Hello World!' let foo = function() { console.log(msg) }; window.module = { foo } })(window)
HTML:html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript" src="index.js"></script> <script type="text/javascript"> module.foo() </script> </body> </html>
JS:java
// index.js (function(window, $) { const str = 'hello world!' const foo = function() { console.log(str) } const bar = function() { console.log('change background color...') $('body').css('background', 'red') } window.module = { foo, bar } })(window, jQuery) // 注入 jQuery
HTML:node
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript" src="jquery-3.1.1.min.js"></script> <script type="text/javascript" src="index.js"></script> <script type="text/javascript"> module.foo() module.bar() </script> </body> </html>
缺點:react
<script>
的引入順序不能改變,不然出錯window
上添加過多的屬性,看起來臃腫且很差維護CommonJS 能夠在服務器端或瀏覽器端實現。jquery
Node.js
,運行時動態加載模塊(同步)Browserify.js
,在轉譯(編譯)時加載打包模塊(生成新文件),修改模塊文件後需從新編譯打包語法 :es6
暴露模塊,至關於暴露一個空對象,單獨使用 exports.someVar
至關於在該空對象上添加成員,使用 module.exports = { ... }
則用新的對象(也能夠是變量或者函數等)代替空對象express
// 1.僅能使用一次,重複使用會覆蓋 module.exports = { ... }; module.exports = function() { ... }; module.exports = 'someVar'; // 2.能屢次使用,默認將全部內容整合成一個對象,至關於 1 中暴露對象 exports.foo = function() { ... }; exports.bar = 'someVar'; // 等同於 module.exports = { foo: function() { ... }, bar: 'someVar' }
引入模塊,將模塊所暴露的對象(也能夠是一個單獨的變量或者函數等)引入npm
// 第三方模塊,直接輸入模塊名 let m1 = require('react'); // 自定義模塊,相對路徑 let m2 = require('./module.js'); // 調用:根據暴露方式調用
1.在服務器端中使用
// module_1.js exports.str = 'hello world!' exports.num = 100 // module_2.js exports.foo = function() { console.log('foo() in module_2.js') } // module_3.js module.exports = { bar: function() { console.log('bar() in module_3.js') } } // module_4.js module.exports = { bar: function() { console.log('bar() in module_3.js') } } // main.js const module_1 = require('./module_1'); const module_2 = require('./module_2'); const module_3 = require('./module_3'); const module_4 = require('./module_4'); console.log(module_1.str, module_1.num); module_2.foo(); module_3.bar(); module_4();
運行 node main.js
的結果:
hello world! 100 foo() in module_2.js bar() in module_3.js baz() in module_4.js
2. 在瀏覽器端中使用
在瀏覽器中使用時,要安裝依賴包 browserify.js
1)下載安裝 browserify.js
// 生成 package.json npm init // 全局安裝 npm install browserify -g // 項目目錄中安裝並添加至 package.json npm install browserify --save-dev
2)基礎目錄
|-project |-dist // 打包生成文件目錄(注:browserify 不會自動生成文件夾,須要手動建立) |-src |-main.js // 主文件 |-module1.js |-module2.js |-module3.js |-module4.js |-index.html |-package.json // 項目配置文件 |-node_modules // 依賴包
其中各 js 文件代碼同上
index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript" src="dist/build.js"></script> </body> </html>
使用 browserify
進行模塊打包:
$ browserify ./src/main.js -o ./dist/build.js
在瀏覽器的控制檯能看到相同的輸出:
hello world! 100 foo() in module_2.js bar() in module_3.js baz() in module_4.js
AMD(Asynchronous Module Definition異步模塊定義) 專用於瀏覽器端,是 異步
加載模塊的。依賴於 require.js
庫
語法步驟:
// 1.定義沒有依賴其餘模塊的模塊, module_1.js define(function() { const str = 'hello world' const foo = function () { return str } return { foo: foo, bar: function() { console.log('bar() in module_1.js') } } }) // 2.定義依賴其餘模塊的模塊, module_2.js // 第一個參數數組是此模塊依賴的全部模塊,並要以形參傳入後一個參數函數 define(['module_1'], function(m1) { const baz = function() { console.log(m1.foo(), 'baz() in module_2.js') } return { baz } });
require
也能夠用 requirejs
// main.js (function() { // 模塊配置:paths 爲各模塊路徑配置,還能夠配置更多的選項,如 baseUrl 等 require.config({ // 注意:模塊路徑不能添加 .js 後綴,引入第三方庫時(jQuery, Angular等),名字必須對應並且爲小寫。 paths: { module_1: './modules/module_1', module_2: './modules/module_2', jquery: './libs/jquery-3.1.1.min' } }); // 引入並使用模塊 require([ 'module_1', 'module_2', 'jquery' ], function(m1, m2, $) { m1.bar(); m2.baz(); $('body').css('background', 'red') }); })();
<body> <!-- data-main:應用源文件main.js的路徑,src:require.js的路徑 --> <script data-main="./js/main.js" src="./js/libs/require.js"></script> </body>
完整步驟
1)下載
在官網下載 RequireJS,保存至文件 require.js
。
2)基礎項目目錄
|-project |-js |-libs // 庫文件夾 |-require.js |-jquery-3.1.1.min.js |-modules // 模塊文件夾 |-module_1.js |-module_2.js |-main.js // 主文件 |-index.html
各 js 文件的內容如語法步驟所示。
index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <!-- src:require.js的路徑 data-main:應用源文件main.js的路徑 --> <script type="text/javascript" data-main="js/main.js" src="./js/libs/require.js"></script> </body> </html>
3)在瀏覽器控制檯的輸出:
bar() in module_1.js 3 hello world baz() in module_2.js // 且頁面背景色爲紅色
CMD(Common Module Definition通用模塊定義),依賴於 sea.js
庫。
語法:
實現語法相似於 browserify.js 和 require.js 的結合。並能夠執行異步加載。
暴露模塊
// 只要暴露了任何內容的模塊,function 都要帶這三個形參 define(function(require, exports, module) { let data = 'in module-1'; let foo = function() { console.log(data); }; // 暴露內容的語法相似於 browserify // 1.暴露一個對象 module.exports = { foo }; // 2.暴露一個方法 module.exports = foo; // 3.分開暴露多個屬性 exports.data = data; exports.foo = foo; });
引入模塊
// 模塊再也不暴露內容時,只寫一個形參 require define(function(require) { // 同步引入 let module1 = require('./module1'); module1.foo(); let module4 = require('./module4'); module4.baz(); // 異步引入 require.async('./module3', function(module3) { module3(); }) });
完整步驟
1)下載
官網下載 sea.js。保存至 'js/libs/sea.js'
2)基礎項目目錄
|-js |-libs |-sea.js |-modules |-module1.js |-module2.js |-module3.js |-module4.js |-|-main.js |-index.html
3)文件
module1.js:
define(function(require, exports, module) { const str = 'In module_1.' exports.fun1 = function() { console.log(str) } })
module2.js:
define(function(require, exports, module) { const module_1 = require('./module_1') module_1.fun1() const fun2 = function() { console.log('In module_2.') } module.exports = { fun2: fun2 } })
module3.js:
define(function(require, exports, module) { const fun3 = function() { console.log('In module_3.') } module.exports = fun3 })
module4.js:
define(function(require, exports, module) { const module_2 = require('./module_2') module_2.fun2() // 異步加載 require.async('./module_3', function(m3) { m3() }) module.exports = { fun4: function() { console.log('In module_4.') } } })
main.js:
define(function(require) { const module_4 = require('./modules/module_4') module_4.fun4() })
index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <!-- 先引入 sea.js --> <script src="./js/libs/sea.js"></script> <script> // 加載模塊 seajs.use('./js/modules/main.js'); </script> </body> </html>
4)在控制檯的輸出:
In module_1. In module_2. In module_4. In module_3.
ES6 模塊化依賴於 babel
(轉換爲ES5語法) 和 browserify.js
(編譯打包模塊),是靜態加載的。
語法:
暴露模塊:
export
或 export default
;export
能夠逐個暴露變量,可是命令要包含對外的接口;export default
定義一個默認暴露的對象(其中 default
就至關於對外的接口);export default
只能使用一次;// 1.逐個暴露,暴露兩個對外接口 arr 和 foo export let arr = [1, 2, 3]; export function foo() { return 'Hello World!'; }; // 2.一次性暴露,1 的另外一種寫法 let str = 'Hello World!'; let bar = function() { console.log(str); }; export { str, bar }; // 3.暴露默認模塊(只能定義一個默認模塊,定義多個至關於覆蓋) export const PI = 3.14 // 暴露一個對外接口 PI let fun1 = function() { return true; }; let fun2 = function() { return false; }; export default { fun1, fun2 } // 默認暴露一個對象
引入模塊:
import
引入模塊(至關於打開與模塊的接口通道,從中取出所需模塊);export
暴露的變量的引入,要一一對應其對外接口;export default
暴露的變量的引入,能夠用別名指定(實質上是對 default
接口的重命名);*
指定引入模塊的全部非默認(default
)暴露的對外接口,使用 as
對對外接口重命名;import
具備提高功能,不要求在代碼的頂部;import
不能動態引入模塊,由於它是靜態加載的;import
和 export
能夠一塊兒使用,具備 "轉發" 模塊的功能,能夠用做各模塊的整合或者跨模塊變量。// 1.引入自定義模塊:非默認暴露 import { foo, bar } from './module1.js'; // .js 後綴能夠省略 import * as m1 from './module1.js'; // 引入模塊的全部對外接口,可以使用 m1.foo, m1.bar // 2.引入自定義模塊:默認暴露 import module3 from './module3.js'; // 不能添加 {} // 3.引入第三方模塊 import $ from 'jquery'; // npm 下載的第三方包,路徑自動調至 node_modules // 4.與 export 一塊兒使用 // index.js export {exp} from './math_module.js' export {data} from './data_module.js' // script.js import {exp, data} from './index.js'
使用步驟
1)安裝
// 初始化 package.json $ npm init // 全局安裝依賴庫 $ npm install babel-cli -g // babel 命令行接口 $ npm install babel-preset-es2015 -g // 用於轉譯 ES6 代碼的庫 $ npm install browserify -g // 編譯打包 ES6 模塊 // 添加項目依賴 $ npm install babel-cli --save-dev $ npm install babel-preset-es2015 --save-dev $ npm install browserify --save-dev // 有必要時,安裝第三方依賴包 $ npm install jquery@1 --save-dev
2)基本項目目錄
|-js |-build // 用 babel 轉譯爲 es2015 語法的模塊文件時生成,不須要本身建立文件夾 |-main.js |-module1.js ... |dist // browserify 打包後的文件,須要本身建立文件夾 |-bundle.js |-src // 模塊文件 |-main.js |-module1.js |-module2.js |-module3.js |-node_modules |-index.html |-.babelrc // babel 配置文件,一個 json 文件,不能添加更多後綴 |-package.json |-package-lock.json
3)文件
.babelrc
{ "presets": ["es2015"] }
module1.js
// 分別暴露多個對外接口 export const str = 'hello world!' export const num = 100 export function fun1() { console.log('In module_1.js') } // 等同於 /* const str = 'hello world!' const num = 100 function fun1() { console.log('In module_1.js') } export { str, num, fun1 } */
module2.js
// 暴露一個對外接口 export function fun2() { console.log('In module_2.js') } // 一個默認暴露 export default function() { console.log('export default in module_2.js') }
module3.js
// 轉發來自 module_1 和 module_2 的對外接口 export { str, num, fun1 } from './module_1' export { fun2 } from './module_2' import dm2 from './module_2' // 默認暴露一個自身的對外接口 export default { str: 'module_3', fun3: function() { console.log(`In ${this.str}.js`) }, dm2 }
main.js
// import * as m3 from './module_3' // import dm3 from './module_3' // 能夠寫爲 import dm3, * as m3 from './module_3' // dm3 接收默認暴露;m3 爲別名,接受全部非默認暴露的接口 import $ from 'jquery' // 第三方庫 m3.fun1() m3.fun2() dm3.fun3() dm3.dm2() console.log(m3.str, m3.num) $('body').css('background', 'red')
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script src="./dist/bundle.js"></script> </body> </html>
4)輸出
In module_1.js In module_2.js In module_3.js export default in module_2.js hello world! 100 // body 背景色爲紅色
區別:
exports
和 export
,module.exports
和 export default
;可是含義卻不同,module.exports
會覆蓋其餘單獨暴露的語句,export default
只是一個額外的默認暴露,不影響單獨暴露的語句ES6 Module 加載 CommonJS Module:
module.exports
,使用第三種方法時,要經過 foo.default()
才能獲取真正的 module.exports
// a.js module.exports = function() { console.log('hello world!') } // 法一 import foo from './a.js' // foo = function() {} foo() // 法二 import { default as foo } from './a.js' // foo = function() {} foo() // 法三 import * as foo from './a.js' // foo = { default: function() {} } foo.default()
// 法一 import * as express from 'express'; const app = express.default(); // 法二 import express from 'express'; const app = express();