一文读懂JavaScript模块化开发(一)
JavaScript
2021-05-21
203
0

JavaScript模块化开发,早期会使用CommonJS或者AMD标准进行开发,但从ES6开始确定了原生支持的模块化标准。本文主要探讨CMD模块化开发和ES模块化标准的使用差异。

CommonJS模块化

CommonJS模块化运用于Node.js开发中,使用require和exports语法来输入和输出。

例如,我们输出a变量和func函数:

exports.a = 1;
exports.func = function(){
    console.log("hello!")
}

那么输入语法可以这样写:

var cmdModule = require("./cmdModule.js");
cmdModule.a     // 1
cmdModule.func  // function

输出的变量和函数在导入时会自动被包裹上一层命名空间(JSON),需要打点去调用所暴露的变量和函数。

此外require语句无论调用几次均只执行一次,在第一次加载时模块会被缓存,之后都从缓存中直接读取结果。

使用exports可以向外暴露很多东西,但如果我们只需要向外暴露一个类,那么此时调用时候会很不方便,例如

输出:

function People(name, age){
    this.name = name;
    this.age  = age;
}
exports.People = People;

调用:

var People = require("./People.js");
var person = new People.People("小明", 18);

可以看到,调用函数new的时候需要写People.People(),十分的麻烦。

如果js文件只需要向外输出一个函数,此时可以使用module.exports = xx的写法。

例如刚才的例子,我们可以改为

输出:

function People(name, age){
    this.name = name;
    this.age  = age;
}
moudle.exports.People = People;

调用:

var People = require("./People.js");
var person = new People("小明", 18);

总结,如果一个js模块要向外暴露很多个变量,那么我们应该使用exports.xx = xx;如果仅仅暴露一个东西,通常是购彩函数,此时我们使用module.exports = xx。

ES模块化

直接罗列需要输出的变量或者函数

export let a = 1;

export function sayHello() {
  console.log("hello!")
}

顶部定义,底部向外暴露:

function calCircleArea(r){
    return Math.PI * Math.sqrt(r);
}

export { calCircleArea }

引入时:

import { calCircleArea, a, sayHello } from "./circle.js";

当然我们还可以给定一个Namespace,引入该包里的所有函数和变量:

import * as Circle from "./circle.js";

如果我们只向外默认暴露一个东西,那么可以使用export default写法:

export default function People(name, age) {
  this.name = name;
  this.age = age;
}

People.prototype.sayHello = function() {
  alert("Hello!");
}

引入时:

import People from "./People.js"

let xiaoming = new People("小明", 18);
xiaoming.sayHello();

注意,这里引入的People是一个Alias,可以起任意的名字,我们不需要纠结到底暴露的是什么函数名。

CommonJS模块和ES模块差异

ES6的设计思想是尽量静态化,能保证在编译时就确定模块之间的依赖关系,每个模块的输入和输出变量也都是确定的,而CommonJS无法在编译时就确定这些内容,只能在运行时确定。其次CommonJS输出的是一个值的拷贝,而ES模块输出的是值的引用。

Reference

ES6Javascript