到目前为止,我们已经看到了如何导入/导出(import/export)多个内容,也可以用“as”语法导入/导出为其他名称。
在开发中,模块包含:
- 一个库,一组函数,就像
lib.js
这样。 - 或者在
user.js
中描述了一个实体,比如class User
这样,整个模块只有这个类。
大部分情况下,开发者倾向于使用第二种方式,因此每个“thing”都存在于自己的模块中。
当然,如果每个文件都需要自己的模块,这就使得文件很多,但是这不算什么大问题。实际上,如果文件命名以及文件夹结构得当,代码导航会变得更容易。
模块提供特殊的默认导出 export default
语法,以使得“一个模块只做一件事”看起来更好。
默认导出要求下列的 export
和 import
语句:
export default
放在模块“主导出(main export)”之前。import
导入时不使用花括号
例如,user.js
导出 class User
:
// 📁 user.js
export default class User { // 只要添加“default”即可
constructor(name) {
this.name = name;
}
}
…在 main.js
中添加导入:
// 📁 main.js
import User from './user.js'; // 不需要花括号 {User}, 仅仅是 User 就可以了
new User('John');
不用花括号的导入看起来很酷。开始使用模块时常见的错误就是忘记花括号。所以请记住,命名导入需要使用花括号,而默认导入不需要。
命名导出 | 默认导出 |
---|---|
export class User {...} |
export default class User {...} |
import {User} from ... |
import User from ... |
当然,每个文件只有一个“默认”导出。
我们可能在单个模块中同时使用默认导出和命名导出,但是在日常开发中,开发者一般不会这样做。模块要么是命名导出要么是默认导出。
另外需要注意的是命名导出必须(理应)具有名称,而 export default
可能是匿名的(没有名称)
例如,下面这些都是完全有效的默认导出:
export default class { // 没有类名
constructor() { ... }
}
export default function(user) { // 没有函数名
alert(`Hello, ${user}!`);
}
// 导出一个值而不使用变量
export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
这些都是可行的,因为每个文件只有一个 export default
。相反,省略命名导入的名称将会出错:
export class { // Error!(非命名导出需要名称)
constructor() {}
}
“Default” 别名
“default”关键词用于默认导出的别名,常用于我们需要引用单独导出和其他脚本的情况。
例如,如果我们已经声明了一个函数,然后导出它 export default
(和定义分开):
function sayHi(user) {
alert(`Hello, ${user}!`);
}
export {sayHi as default}; // 和我们在函数前添加“export default”一样
又如,假设模块 user.js
导出一个默认导出“default”和几个命名导出(虽然很少出现,但是会发生):
// 📁 user.js
export default class User {
constructor(name) {
this.name = name;
}
}
export function sayHi(user) {
alert(`Hello, ${user}!`);
}
那么,如何导入默认导出和命名导出:
// 📁 main.js
import {default as User, sayHi} from './user.js';
new User('John');
再如,我们想要把 *
作为对象导入,那么 default
属性就是默认导出:
// 📁 main.js
import * as user from './user.js';
let User = user.default;
new User('John');
我应该使用默认导出吗?
开发者应该谨慎使用默认导出,因为这将会使代码更难维护。
命名导出是显式的。它们准确命名导入的内容,因此我们能得到更多的信息,这对于代码阅读与维护都是非常有利的。
此外,命名导出会强制我们使用正确的名称来导入:
import {User} from './user.js';
// 使用 {MyUser} 导入将不起作用,导入名字应该为 {User}
对于默认导出,我们总是在导入时选择名称:
import User from './user.js'; // works
import MyUser from './user.js'; // works too
// 使用任何名称导入都没有问题
对于相同的导入,团队成员可能使用不同的命名,因此,默认导入的命名可能会被滥用,
通常,为了避免这种情况并保持代码的整洁一致,可以遵从这条规则,即导入的变量应该与文件名相对应,例如:
import User from './user.js';
import LoginForm from './loginForm.js';
import func from '/path/to/func.js';
...
另一种解决方案是在任何地方都使用命名导出。即使只导出一个东西,也仍然使用命名导出,而不是默认导出 default
。