JavaScript教程

模块化和ES6模块

Preview
  • JavaScript模块化和ES6模块
  • CommonJS模块化规范
  • module.exports
  • require
  • exports和module.exports的区别
  • AMD模块化规范
  • define
  • require
  • ES6模块
  • export
  • import
  • 总结

JavaScript模块化和ES6模块

JavaScript模块化是指将一个大的JavaScript程序分成若干个小的模块,每个模块只关注自己的功能,通过模块化的方式可以提高代码的可维护性和可复用性。在ES6之前,JavaScript并没有官方的模块化规范,因此出现了一些非官方的模块化规范,如CommonJS、AMD、CMD等。而ES6模块则是JavaScript官方的模块化规范。

CommonJS模块化规范

CommonJS模块化规范是Node.js采用的模块化规范。在CommonJS中,每个模块都是一个单独的文件,文件内部定义的变量、函数、类等只在该模块内部可见,如果想在其他模块中使用,需要通过module.exports和require来实现。

module.exports

module.exports用于指定一个模块对外暴露的接口,可以是任意类型的值,如变量、函数、对象等。

// moduleA.js
let a = 1;
function test() {
  console.log('test');
}
module.exports = {
  a,
  test
}

require

require用于引入其他模块暴露的接口。在使用require时,需要指定要引入的模块路径,如果是当前目录下的模块,需要使用./或../来指定路径。require会缓存已经引入的模块,如果多次引入同一个模块,只会执行一次该模块的代码。

// moduleB.js
let moduleA = require('./moduleA');
console.log(moduleA.a); // 1
moduleA.test(); // test

exports和module.exports的区别

在CommonJS中,exports和module.exports都可以用于指定模块对外暴露的接口,但是它们有一些区别。

exports实际上是module.exports的一个引用,如果直接给exports赋值,相当于给module.exports赋值,例如:

// moduleA.js
exports.a = 1;
exports.test = function() {
  console.log('test');
}

// 等价于
module.exports.a = 1;
module.exports.test = function() {
  console.log('test');
}

但是,如果直接给exports赋值一个新的对象,exports将不再是module.exports的引用,例如:

// moduleA.js
exports = {
  a: 1,
  test: function() {
    console.log('test');
  }
}

// 不等价于
module.exports = {
  a: 1,
  test: function() {
    console.log('test');
  }
}

因此,如果要指定一个模块对外暴露的接口,最好使用module.exports。

AMD模块化规范

AMD(Asynchronous Module Definition)模块化规范是由RequireJS提出的,主要用于浏览器端的模块化开发。在AMD中,每个模块都是一个单独的文件,文件内部定义的变量、函数、类等只在该模块内部可见,如果想在其他模块中使用,需要通过define和require来实现。

define

define用于定义一个模块,其中第一个参数是依赖列表,第二个参数是模块构造函数,该函数返回模块的接口。

// moduleC.js
define(['./moduleA'], function(moduleA) {
  let b = 2;
  function test() {
    console.log('test');
  }
  return {
    b,
    test,
    a: moduleA.a
  }
})

require

require用于引入其他模块暴露的接口。在使用require时,需要指定要引入的模块路径,如果是当前目录下的模块,需要使用./或../来指定路径。

// moduleD.js
require(['./moduleC'], function(moduleC) {
  console.log(moduleC.a); // 1
  console.log(moduleC.b); // 2
  moduleC.test(); // test
})

ES6模块

ES6模块是JavaScript官方的模块化规范,其语法更加简洁明了,支持静态分析和优化,而且可以在浏览器端和Node.js环境中使用。在ES6中,每个模块都是一个单独的文件,文件内部定义的变量、函数、类等只在该模块内部可见,如果想在其他模块中使用,需要通过export和import来实现。

export

export用于指定一个模块对外暴露的接口,可以是任意类型的值,如变量、函数、类等。在ES6中,可以使用export default指定一个默认的模块接口,例如:

// moduleE.js
export let c = 3;
export function test() {
  console.log('test');
}
export default function() {
  console.log('hello world');
}

在上面的例子中,使用export指定了三个模块接口,其中一个使用了export default指定为默认接口。

import

import用于引入其他模块暴露的接口。在使用import时,需要指定要引入的模块路径,如果是当前目录下的模块,需要使用./或../来指定路径。可以使用import * as来引入所有的模块接口,例如:

// moduleF.js
import { c, test } from './moduleE';
import sayHello from './moduleE';
console.log(c); // 3
test(); // test
sayHello(); // hello world

在上面的例子中,使用import引入了moduleE模块中的c和test接口,使用import引入了moduleE模块的默认接口sayHello。

总结

JavaScript模块化可以提高代码的可维护性和可复用性,常见的模块化规范包括CommonJS、AMD等。ES6模块是JavaScript官方的模块化规范,其语法更加简洁明了,支持静态分析和优化,而且可以在浏览器端和Node.js环境中使用。在ES6中,使用export和import来指定模块的接口,export可以指定多个接口,也可以使用export default指定一个默认接口,import可以引入指定的接口,也可以使用import * as引入所有的接口。