CommonJs/ES6/AMD模塊的用法以及區別

github地址:
一直以來對CommonJs/AMD/CMD/ES6的文件模塊加載一直懵懵懂懂。甚至有時會將CommonJs的exports和ES6的export.default搞混。趁着學習webpack,先搞懂這些模塊加載方式再說!!!javascript

隨着前端的發展,咱們平常開發的功能愈來愈複雜,文件愈來愈多。隨後前端社區衍生出了CommonJs/AMD/CMD/ES6的幾種模塊加載方式。html

模塊加載方式

  1. CommonJs
  2. ES6
  3. AMD
  4. CMD

01: CommonJs

參考地址:阮一峯老師講解的CommonJs規範
每一個文件都是一個單獨的模塊,有本身的做用域。在一個文件裏面定義的變量、函數、類,都是私有的,對其餘文件不可見。
CommonJS規範規定,每一個模塊內部,module變量表明當前模塊。這個變量是一個對象,它的exports屬性(即module.exports)是對外的接口。加載某個模塊,實際上是加載該模塊的module.exports屬性。前端

CommonJs的特色
  1. 全部的代碼都運行在模塊做用域,不會污染全局做用域;
  2. 模塊能夠屢次加載,可是隻會在第一次加載時運行一次,而後運行的結果就會被緩存了,之後再加載就直接讀取緩存結果。要想讓模塊繼續運行,必須清空緩存;
  3. 模塊加載順序,按照其在代碼中出現的順序;
  4. CommonJs加載模塊是同步的;
Module對象

咱們在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對象的兩個屬性,numperson,在main.js中使用了ES6的對象擴展來接收對應的值。

module.exportsexports(這點只須要了解便可,在開發過程當中,建議使用module.exports

爲了方便,Node爲每一個模塊提供一個exports變量,指向module.exports。這等同在每一個模塊頭部,有一行這樣的命令

var exports = module.exports;

可是須要注意的是,不能直接將exports變量指向一個值,這種行爲至關於切斷了exportsmodule.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

02: ES6

參考地址:《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));
默認輸出 export default

e3.js

export default function(){
  return '123'
}

main.js

import name from './e3';
console.log(name()); // 123

注意:使用默認輸出時,import不使用{},使用正常輸出時,import須要使用{}!!!

03: AMD

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));
})
相關文章
相關標籤/搜索