github地址:
一直以來對CommonJs/AMD/CMD/ES6的文件模塊加載一直懵懵懂懂。甚至有時會將CommonJs的exports和ES6的export.default搞混。趁着學習webpack,先搞懂這些模塊加載方式再說!!!javascript
隨着前端的發展,咱們平常開發的功能愈來愈複雜,文件愈來愈多。隨後前端社區衍生出了CommonJs/AMD/CMD/ES6的幾種模塊加載方式。html
參考地址:阮一峯老師講解的CommonJs規範
每一個文件都是一個單獨的模塊,有本身的做用域。在一個文件裏面定義的變量、函數、類,都是私有的,對其餘文件不可見。
CommonJS
規範規定,每一個模塊內部,module
變量表明當前模塊。這個變量是一個對象,它的exports
屬性(即module.exports
)是對外的接口。加載某個模塊,實際上是加載該模塊的module.exports
屬性。前端
咱們在demo01中建立兩個js文件,名爲c1.js
,main.js
c1.js
每一個模塊內部都有一個module
對象,表明當前模塊。它有如下屬性:java
module.id
模塊的識別符,一般是帶有絕對路徑的模塊文件名。module.filename
模塊的文件名,帶有絕對路徑。module.loaded
返回一個布爾值,表示模塊是否已經完成加載。module.parent
返回一個對象,表示調用該模塊的模塊。module.children
返回一個數組,表示該模塊要用到的其餘模塊。module.exports
表示模塊對外輸出的值。
console.log(module);
在命令行中執行node
node c1.js
輸出結果爲webpack
Module { id: '.', exports: {}, parent: null, filename: '/Users/Desktop/demo01/c1.js', loaded: false, children: [], paths: [] }
其中主要關注的是module.exports
這個屬性,它表示當前模塊對外輸出的接口,其餘文件加載該模塊,實際上就是讀取module.exports變量。git
注意:一下都在node環境中執行,也就是使用命令行node xxx.js
來執行的由於CommonJs是在node環境中運行的。es6
建立一個c2.js
文件github
c2.js
建立一個對象c2
,經過module.exports
把該對象暴露,在main.js
中,使用require
進行接收。web
let c2 = { num: 5, sum: function(a,b){ return a+ b }, person: { name: 'wbin', age: '25' } } module.exports = c2;
main.js
let c2 = require('./c2'); console.log(c2); // { num: 5,sum: [Function: sum],person: { name: 'wbin', age: '25' } }
若是要暴露具體內容
建立c3.js
c3.js
let c3 = { num: 5, sum: function(a,b){ return a+ b }, person: { name: 'wbin', age: '25' } } module.exports.num = c3.num; module.exports.person = c3.person;
main.js
let {num, person} = require('./c3'); console.log(num, person); // 5 { name: 'wbin', age: '25' }
在c3.js
中,我暴露出c3
對象的兩個屬性,num
和person
,在main.js
中使用了ES6的對象擴展來接收對應的值。
module.exports
和exports
(這點只須要了解便可,在開發過程當中,建議使用module.exports
)爲了方便,Node
爲每一個模塊提供一個exports
變量,指向module.exports
。這等同在每一個模塊頭部,有一行這樣的命令
var exports = module.exports;
可是須要注意的是,不能直接將exports
變量指向一個值,這種行爲至關於切斷了exports
和module.exports
的關係
在demo01中建立c4.js
c4.js
let c4 = { num: 5, sum: function(a,b){ return a+ b }, person: { name: 'wbin', age: '25' } } exports = c4;
main.js
let c4 = require('./c4'); console.log(c4); // {}
以上輸出結果是無效的,是一個空對象。
正確的寫法是
c4.js
let c4 = { num: 5, sum: function(a,b){ return a+ b }, person: { name: 'wbin', age: '25' } } exports.c4 = c4;
爲了防止這種沒必要要的錯誤,建議使用module.exports
參考地址:《ES6入門》第22和23章
ES6模塊的設計是儘量的靜態化,使得編輯時就能肯定模塊之間的依賴關係,以及輸入和輸出變量。而CommonJs和AMD則是在運行時才能實現以上結果。
例如CommonJs模塊就是一個對象,輸入時必須查找對象屬性,而ES6模塊則能夠暴露出任何變量、函數等。
因此說ES6模塊的加載方式是「編譯時「加載或者是靜態加載。
ES6模塊功能主要由兩個命令構成:export和import。export用來規定模塊的對外接口,import用來輸入其餘模塊提供的功能。
demo02e1.js
可使用export暴露變量
var firstName = 'w'; var lastName = 'bin'; var year = 1993; export {firstName, lastName ,year};
也能夠暴露fun
export function mul(a, b){ return a * b; }
通常狀況下,export輸出的變量就是原本的名字,可是可使用as進行重命名。進行重命名以後咱們能夠給某個變量(多是fun)這些進行屢次輸出。
function add(a, b){ return a + b; } function reduce(a, b){ return a - b; } export { add as sum, reduce as mius, reduce as jian }
須要注意的是:ES6模塊的import/export
目前不支持在node環境中直接使用,可使用webpack打包以後在瀏覽器中查看效果
使用import來加載某個模塊
e2.js
export let name = 'wbin'; export let age = 26;
main.js
import {name, age} from './e2'; console.log(name, age);
import命令接收一個大括號{},裏面指定要從其餘模塊加載的變量名。須要注意的是加載的變量名必須和export輸出的變量名一致。可是咱們能夠在improt中給該名稱從新命名。
import {name as wbin, age} from './e2'; console.log(wbin, age);
有時咱們須要總體加載所須要的模塊,可使用*號來加載
circle.js
export function area(radius) { return (Math.PI * radius * radius); } export function circumference(radius){ return 2 * Math.PI * radius; }
main.js
// 總體引入 import * as circle from './circle'; console.log(circle.area(2),circle.circumference(2));
e3.js
export default function(){ return '123' }
main.js
import name from './e3'; console.log(name()); // 123
注意:使用默認輸出時,import不使用{},使用正常輸出時,import須要使用{}!!!
AMD是"Asynchronous Module Definition"的縮寫,意思就是"異步模塊定義"。它採用異步方式加載模塊,模塊的加載不影響它後面語句的運行。全部依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成以後,這個回調函數纔會運行。
AMD也採用require()語句加載模塊,它要求兩個參數:
require([module], callback);
在demo03文件夾中建立幾個文件 index.html,main.js,sum.js,all.js以及簡單的webpack配置 webpack.config.js
webpack.config.js
module.exports = { entry: { bundle: './main.js' }, output: { filename: '[name].js' }, mode: 'development' }
sum.js
define(function(){ return { sum: function(a, b){ return a + b; } } })
main.js
require(['./sum'],function(sum){ console.log(sum.sum(1,2)); })