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


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

隨着前端的發展,我們日常開發的功能越來越復雜,文件越來越多。隨后前端社區衍生出了CommonJs/AMD/CMD/ES6的幾種模塊加載方式。

模塊加載方式

  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對象,代表當前模塊。它有以下屬性:

  • module.id 模塊的識別符,通常是帶有絕對路徑的模塊文件名。
  • module.filename 模塊的文件名,帶有絕對路徑。
  • module.loaded 返回一個布爾值,表示模塊是否已經完成加載。
  • module.parent 返回一個對象,表示調用該模塊的模塊。
  • module.children 返回一個數組,表示該模塊要用到的其他模塊。
  • module.exports 表示模塊對外輸出的值。
console.log(module);

在命令行中執行

node c1.js

輸出結果為

 Module {
  id: '.',
  exports: {},
  parent: null,
  filename: '/Users/Desktop/demo01/c1.js',
  loaded: false,
  children: [],
  paths:
   [] }

其中主要關注的是module.exports這個屬性,它表示當前模塊對外輸出的接口,其他文件加載該模塊,實際上就是讀取module.exports變量。

注意:一下都在node環境中執行,也就是使用命令行node xxx.js 來執行的因為CommonJs是在node環境中運行的。

創建一個c2.js文件

c2.js
創建一個對象c2,通過module.exports把該對象暴露,在main.js中,使用require進行接收。

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));
})


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM