前端小白轻松掌握JavaScript模块导入导出:这次一定能搞懂导出与导入那些事儿!

1,281 阅读6分钟

作为一个刚入门前端开发的小白,我开始接触前端模块化开发的时候,可以导出一个文件中的方法,并在另一个文件中导入这些方法。一开始感觉还挺有意思,但用了整整一天后,发现这导入导出模块还有几种不同操作,还遇到了一些错误。正好趁机梳理一下知识:为什么有的地方导入需要大括号,而有的地方却不用?如果导入的方法跟本地方法冲突了,哪个方法会生效?

这里主要是使用ES6语法的模块导入导出,还有另外一种导入导出方式是CommonJS的,ES和CommonJS的区别可以参考:《前端小白也能懂:ES模块和CommonJS的那些事》,接下来我们先看一下两种模块导出方法的定义

定义

在JavaScript中,命名导出(Named Exports)和默认导出(Default Exports)是ES6引入的模块系统中的两种导出方式,它们允许你从一个文件导出多个值或者从一个文件导出一个主要的值。导出的内容可以是任何 JavaScript 值,包括函数、类、对象、数组、字符串、数字、布尔值、nullundefined(但通常不会导出 undefined,因为它没有实际的导出价值)等。

命名导出

命名导出允许你从一个文件中导出多个值每个值都有一个特定的名称。这意味着你可以从一个文件中导出多个函数、对象、变量等,然后在另一个文件中通过它们的名称单独导入,每次导入时,你必须使用完全相同的名称。

默认导出

默认导出允许你从一个文件中导出一个主要的值。这意味着你可以导出一个函数、一个类或者其他任何值,而不需要指定一个特定的名称默认导出在导入时可以被任意命名


接着,我会根据一般开发的使用情况,我将其分成了几个部分:导出整个文件内容、导出函数、导出类和变量,最后附上一些奇技淫巧

用法

命名导出

要使用命名导出整个文件,第一种写法是在每个要导出的内容(函数、类、变量等)前加上export(不带 default)。如下所示:

// module.js
export function xiaodou() {
    console.log("xiaodou")
}

export function dadou() {
    console.log("dadou")
}

第二种写法是用一个命名导出来导出一个模块中所有的导出项。这可以通过使用export { ... }语法来实现,其中...代表所有需要导出的标识符。如下所示:

// module.js
function xiaodou() {
    console.log("xiaodou")
}

function dadou() {
    console.log("dadou")
}
export { xiaodou, dadou }

两种写法有什么区别和使用建议呢?

  • 单独导出可以让你清晰地知道每个导出项是什么,这有助于提高代码的可读性和可维护性。如果模块中导出的项数量适中(少于5个),并且每个导出项都有明确的用途和名称,那么推荐使用单独导出可能更加清晰。
  • 如果模块中导出的项非常多,那么使用一次性导出所有项的方法可以提高代码的整洁性,并且减少重复的代码行数。但是这会降低代码的可读性。

接下来我们看看怎么导入使用,第一种是使用花括号{}来指定要从module.js导入的选择项,这里可以按需导入需要的内容,有一点需要注意:命名导出是区分大小写的,确保在导入和导出时使用相同的名称。如下所示:

import { xiaodou, dadou } from './module.js'

xiaodou() // 输出 "xiaodou"
dadou() // 输出 "dadou"

如果我们想要导入module.js中所有的命名导出,你可以使用* as语法:

import * as myModule from './module.js';

myModule.xiaodou(); // 输出 "xiaodou"
myModule.dadou(); // 输出 "dadou"

默认导出:多个函数

这里涉及到关键词default,导出的时候,使用关键词加上大括号包括所有的方法变量等

// module.js
function xiaodou() {
    console.log("xiaodou")
}

function dadou() {
    console.log("dadou")
}

export default { xiaodou, dadou }

导入的时候可以使用任意的名字作为模块的别名,比如下面代码中使用的myModule,你也可以使用yourModule,虽然怎么搞都行,但是要注意一下变量命名规范。

import myModule from './module.js'

myModule.xiaodou() // 输出 "xiaodou"
myModule.dadou() // 输出 "dadou"

默认导出:单个函数

如果有一个主要的函数,并希望它是模块的默认导出时,咱们可以直接导出函数,如下所示:

// module.js
function xiaodou() {
    console.log('Hello xiaodou!')
}

export default xiaodou

// 或者下面这种写法
export default function xiaodou() {
     console.log('Hello xiaodou!');
}

在另一个文件中,我们可以使用任意名称导入它,这里导入的是单个函数,所以直接使用,不再涉及到模块名

import dadou from './module.js'

// 调用默认导出的函数,输出: Hello xiaodou!
dadou()

重新导出(Re-exports)

你还可以从其他模块导入内容,并立即导出它们。这有时被称为“重新导出”或“聚合导出”。将多个模块的导出集成到一个单一接口时非常有用。下面是一个简单的例子,它展示了如何从两个不同的模块重新导出内容:

// first.js
// 第一个模块导出一个默认函数和一个命名函数
export default function defaultExport() {
    console.log('This is the default export from first.js');
}

export function namedFunction() {
    console.log('This is a named export from first.js');
}
// second.js
// 第二个模块导出两个命名函数
export function anotherFunction() {
    console.log('This is another function from second.js');
}

export function oneMoreFunction() {
    console.log('This is one more function from second.js');
}

下面使用index.js文件重新导出了first.jssecond.js中的导出项。这使得外部文件可以导入index.js来访问这些导出项,而无需知道它们实际来自哪个文件。

// index.js
// index.js重新导出来自first.js和second.js的导出
export { default as myDefaultFunction } from './first.js';
export { namedFunction } from './first.js';

export { anotherFunction, oneMoreFunction } from './second.js';

xiaodou.js能够一次性导入并使用所有需要的函数,而无需单独导入每个模块。这是一种组织代码和简化导入语句的好方法。

// xiaodou.js
import myDefaultFunction, { namedFunction, anotherFunction, oneMoreFunction } from './index.js';

myDefaultFunction(); // 输出 "This is the default export from first.js"
namedFunction();     // 输出 "This is a named export from first.js"
anotherFunction();   // 输出 "This is another function from second.js"
oneMoreFunction();   // 输出 "This is one more function from second.js"

常见问题

如果导入的方法跟本地方法冲突了,哪个方法会生效?

假设你有一个本地方法add,同时你尝试从一个模块中导入一个同名的add方法:

// 本地方法
function add(a, b) {
  return a + b;
}

// 从模块中导入add方法
import { add } from 'some-module';

// 调用add方法
console.log(add(1, 2));

在这种情况下,调用add(1, 2)时,将会执行本地定义的add函数,而不是从some-module导入的add函数。

如果你希望使用导入的模块中的方法,即使本地定义了同名方法,你可以通过重命名导入的方法来避免冲突:

// 本地方法
function add(a, b) {
  return a + b;
}

// 从模块中导入add方法并重命名
import { add as importedAdd } from 'some-module';

// 调用导入的add方法
console.log(importedAdd(1, 2));

现在,当你调用importedAdd时,它将调用从模块导入的add函数。