JavaScript中的模块系统

前言

在前端开发发展的趋势中,已经越来越偏向于webapp模式,前端更像是app,但是现在的JavaScript语言中,没有原生的包的概念,这和JavaScript的历史有很大原因,由于Google开源的v8引擎以及NodeJS开源项目的成功,使得现在JavaScript的应用场景越来越多,但是原生不支持模块系统的问题一直存在,社区和Ecma提供了很多的解决方案,本文介绍其中一些比较知名的规范,如CommonJS、AMD等......

规范简介

CommonJS

CommonJS 规范规定通过require方法加载包,通过exports来导出,NodeJS就是使用CommonJS规范来管理包

// a.js
const value = {
  num: 0,
  name: 'a.js'
}

module.exports = value

//b.js
const a = require('./a.js')

console.log(a.num) // 0
console.log(a.name) // a.js

AMD

AMD全称Asynchromous module Definition,它的应用场景主要在前端文件加载上,它规定通过define方法声明包,通过require方法加载包,如果包有其他依赖需要在define方法中传入

define('a', ['b'], function (b) {
  return {
    name: 'module a',
    dependencies: 'module b'
  }
})

require('a', function (a) {
  
  console.log(a.name) // module a 
  console.log(a.dependencies) // module b    
  
})

CMD

CMD全称Common Module Definition,和AMD类似,并与CommonJS保持兼容

define(function(require, exports, module) {
  var $ = require('jquery');
  var Spinning = require('./spinning');
  exports.doSomething = ...
  module.exports = ...
})

UMD

UMD官方的Github是这样介绍的

The UMD pattern typically attempts to offer compatibility with the most popular script loaders of the day (e.g RequireJS amongst others). In many cases it uses AMD as a base, with special-casing added to handle CommonJS compatibility.

UMD作为CommonJS和AMD规范的兼容

(function (window, cb){
  
  // 检查exports对象是否存在
  if (typeof exports === 'object') {
    exports = cb()
  } else if ( typeof define === 'function' && define.amd ) {
    define(cb)
  } else {
    window.eventUtil = cb()
  }

})(this, function(){
  // 模块逻辑代码
})

ES6

EcmaScript6中添加了JavaScript的元素模块规范,通过import来引入模块,export导出模块

// a.js
export const a = {
  name: 'value "a" in a.js'
}

// b.js
import * as a from './a.js'

console.log(a.a.name) // value "a" in a.js

参考文章

关于 CommonJS AMD CMD UMD

webpack中文文档-模块系统