《解锁 JavaScript 模块化:导入导出实战指南》

207 阅读5分钟

《解锁 JavaScript 模块化:导入导出实战指南》

各种模块化的导入导出,总是傻傻分不清,碰到就是一团浆糊,就是分不清,今天来整理一下。

CommonJS 模块

导出:

module.exports = {
  name: 'John',
  age: 25
};

在这个例子中,使用 module.exports 对象来导出模块的内容。您可以将任何数据结构、函数、对象等赋值给 module.exports ,使其能够被其他模块导入和使用。

例如,如果模块中还定义了一个函数:

function greet() {
  console.log('Hello!');
}
module.exports = {
  name: 'John',
  age: 25,
  greet: greet
};

导入:

const person = require('./person');
console.log(person.name); 

通过 require('./person') 语句来导入名为 person 的模块。这里的 './person' 表示相对路径。导入后,得到的模块内容被赋值给变量 person ,然后可以通过 person 对象来访问导出的属性和方法。

ES6 模块

export导出:

// 导出单个值
export const num = 5;

使用 export 关键字来导出单个常量。

// 导出函数
export function add(a, b) {
  return a + b;
}

直接在函数定义前加上 export 来导出函数。

// 导出类
export class Person {
  constructor(name) {
    this.name = name;
  }
}

在类定义前加上 export 导出类。

// 导出多个值
const name = 'Alice';
const age = 30;
export { name, age };

先定义多个值,然后使用 export { 变量名 1, 变量名 2 } 的形式来一次性导出多个值。

导入:

// 导入单个值
import { num } from './module';

通过 import 语句,使用花括号指定要导入的单个导出值。

// 导入函数
import { add } from './module';

同样使用花括号指定要导入的函数。

// 导入类
import { Person } from './module';

导入类的方式与导入其他值相同。

// 导入多个值
import { name, age } from './module';

一次性导入多个值。

默认导出:

在 Vue 项目中,当使用 export default 导出默认值时,在导入时有一些特点和需要注意的地方。

首先,export default 用于指定模块的默认导出值。这意味着一个模块可以有且只有一个默认导出。

例如,创建一个名为 myComponent.js 的文件:

// myComponent.js
export default {
  name: 'MyComponent',
  methods: {
    myMethod() {
      console.log('This is a method in the component');
    }
  }
}

在另一个模块中导入这个默认导出值时,可以使用以下方式:

// 其他模块
import MyComponent from './myComponent';

// 可以直接使用导入的默认值
MyComponent.myMethod();

需要注意的是,在导入默认导出值时,您可以使用任何您喜欢的名称来接收这个值。例如,以下导入方式也是完全合法的:

import CustomName from './myComponent';

这与使用 export 导出多个值有所不同。当使用 export 导出多个值时,导入时需要使用花括号 {} 来明确指定要导入的具体名称。

另外,默认导出值可以是任何类型的数据,比如函数、对象、字符串、数字等。

例如:

// 导出一个函数作为默认值
export default function calculateSum(a, b) {
  return a + b;
}

// 导入并使用
import calculate from './calculateSum';
console.log(calculate(10, 20));

或者:

// 导出一个字符串作为默认值
export default 'Hello, Vue!';

// 导入并使用
import message from './message';
console.log(message);

总之,export default 提供了一种简洁的方式来指定模块的主要输出值,使得在导入时更加灵活和方便。

export和export default同时存在

在一个 JavaScript 模块中,是可以同时存在 export default 和 export 的。

例如,以下是一个同时包含默认导出和命名导出的模块示例:

// myModule.js
export function myFunction() {
  // 函数的实现
  console.log('This is a named export function');
}

export const myConstant = 42;

export default {
  myProperty: 'Default property value'
}

在另一个模块中导入时,可以这样做:

import defaultExport, { myFunction, myConstant } from './myModule';

// 使用默认导出
console.log(defaultExport.myProperty);

// 使用命名导出
myFunction();
console.log(myConstant);

这样的设计使得模块可以灵活地提供主要的默认导出值,同时还能暴露多个其他相关的可复用的命名导出,以满足不同的使用场景和需求。

AMD 模块(Asynchronous Module Definition)

想象一下 AMD 模块就像是一个工厂。

define 函数就好比是这个工厂的建设规划。

规划里的第一个参数 ['dep1', 'dep2'] ,可以理解为这个工厂在生产过程中需要的原材料清单,比如 dep1 是钢材,dep2 是塑料。

第二个参数,也就是那个回调函数,就像是工厂的生产线。生产线上的 dep1 和 dep2 就是已经运到生产线上的钢材和塑料。

在这个生产线上,工厂最终生产出一个产品,也就是通过返回的对象 { name: 'AMD Module' } ,这个产品就是这个工厂向外输出的东西。

而 require 函数呢,就像是一个客户下订单。['module'] 就是客户指定要的某个产品,比如就是我们刚刚说的那个工厂生产的产品。

当这个订单完成,也就是模块加载好之后,通过回调函数的参数 module ,客户就拿到了他想要的产品,然后就可以对这个产品进行使用,比如查看、操作等。

再给您举个更具体的例子。比如说我们要做一个游戏,有一个模块是负责生成地图,叫 mapModule 。

它依赖于另一个模块 tileModule (提供各种地图块)和 enemyModule (生成敌人)。

define 函数可能像这样:

define(['tileModule', 'enemyModule'], function(tileModule, enemyModule) {
  return {
    generateMap: function() {
      // 使用 tileModule 和 enemyModule 来生成地图
      return '生成的地图数据';
    }
  };
});

虽然代码内部没有直接写明 mapModule ,但根据 AMD 的约定,这个模块就被默认命名为 mapModule 。

然后在游戏的其他部分,使用这个地图模块时:

require(['mapModule'], function(mapModule) {
  const gameMap = mapModule.generateMap();
  // 后续使用生成的地图进行游戏逻辑处理
});

require 函数用于加载模块,并在回调函数中获取加载的模块对象进行使用。

UMD 模块(Universal Module Definition)

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['dep1', 'dep2'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        module.exports = factory(require('dep1'), require('dep2'));
    } else {
        // 全局变量
        root.returnExports = factory(root.dep1, root.dep2);
    }
}(this, function (dep1, dep2) {
    return {
        name: 'UMD Module'
    };
}));

UMD 模块的目的是使模块在不同的环境(如 AMD 环境、CommonJS 环境、浏览器全局环境)中都能正确工作。它通过判断当前环境的类型来决定如何导出模块。如果支持 AMD ,就按照 AMD 方式导出;如果支持 CommonJS ,就按照 CommonJS 方式导出;否则,将模块对象赋给全局变量。