Javascript(ES6),导出const vs export默认值

ajm*_*jma 175 javascript ecmascript-6 es6-modules

我试图确定这两个之间是否存在任何重大差异,除了能够通过以下方式导入export default:

import myItem from 'myItem';
Run Code Online (Sandbox Code Playgroud)

使用export const我可以做:

import { myItem } from 'myItem';
Run Code Online (Sandbox Code Playgroud)

我想知道除此之外是否存在任何差异和/或用例.

Dav*_*ret 283

它是命名导出与默认导出.export const是带有export关键字的命名导出.

默认导出(const)

每个文件可以有一个默认导出.导入时,您必须指定名称并导入,如下所示:

import MyDefaultExport from "./MyFileWithADefaultExport";
Run Code Online (Sandbox Code Playgroud)

你可以给这个你喜欢的名字.

命名导出(export)

使用命名导出,每个文件可以有多个命名导出.然后导入您想要在大括号中包围的特定导出:

// ex. importing multiple exports:
import { MyClass, MyOtherClass } from "./MyClass";
// ex. giving a named import a different name by using "as":
import { MyClass2 as MyClass2Alias } from "./MyClass2";

// use MyClass, MyOtherClass, and MyClass2Alias here
Run Code Online (Sandbox Code Playgroud)

或者将所有命名导出导入到对象中:

import MyDefaultExport, { MyClass, MyOtherClass} from "./MyClass";
Run Code Online (Sandbox Code Playgroud)

您可以同时使用默认导出或命名导出或两者.语法有利于默认导出更简洁,因为它们的用例更常见(请参阅此处的讨论).

请注意,默认导出实际上是具有名称的命名导出,export default因此您可以通过执行以下操作来导入它:

import * as MyClasses from "./MyClass";
// use MyClasses.MyClass, MyClasses.MyOtherClass and MyClasses.default here
Run Code Online (Sandbox Code Playgroud)

  • 感谢您花时间写这篇文章,它帮助了很多! (16认同)

vsy*_*ync 15

export default影响导入模块时应使用的导入语法的方式.

我喜欢(和使用)的一个有用的用例是允许导出匿名函数而不必明确地命名它,并且只有在导入该函数时,才必须给它一个名称:


例:

module_1

export function divide( x ){
    return x / 2;
}

// only one 'default' function may be exported and the rest (above) must be named
export default function( x ){  // <---- declared as a default function
    return x * x;
}
Run Code Online (Sandbox Code Playgroud)

module_2

// The default function should be the first to import (and named whatever)
import square, {divide} from './module_1.js'; // I named the default "square" 

console.log( square(2), divide(2) ); // 4, 1
Run Code Online (Sandbox Code Playgroud)

import语法用于导入函数(或变量)时,意味着导出的任何内容在导出时已经被命名,因此必须使用完全相同的名称导入它,否则导入将无效.


错误的例子:

  1. 必须首先导入默认功能

    import {divide}, square from './module_1.js
    
    Run Code Online (Sandbox Code Playgroud)
  2. default没有导出default,因此不会导入任何内容

    import {divide_1} from './module_1.js
    
    Run Code Online (Sandbox Code Playgroud)
  3. {}未导出divide_1,因为它module_1.js告诉引擎仅显式搜索命名导出.

    import {square} from './module_1.js
    
    Run Code Online (Sandbox Code Playgroud)


Phi*_*umi 9

次要注意:请注意,从默认导出导入时,命名完全独立.这实际上对重构有影响.

假设您有一个Foo类似这样的类,并带有相应的导入:

export default class Foo { }

//the name 'Foo' could be anything, since it's just an
//identifier for the default export
import Foo from './Foo'
Run Code Online (Sandbox Code Playgroud)

现在,如果您重构您的FooBar并重命名该文件,大多数IDE将不会触及您的导入.所以你最终得到这个:

export default class Bar { }

//the name 'Foo' could be anything, since it's just an
//identifier for the default export.
import Foo from './Bar'
Run Code Online (Sandbox Code Playgroud)

特别是在Typescript中,我非常感谢命名导出和更可靠的重构.区别在于缺少default关键字和花括号.由于您现在进行了类型检查,因此btw还可以防止您在导入中输入拼写错误.

export class Foo { }

//'Foo' needs to be the class name. The import will be refactored
//in case of a rename!
import { Foo } from './Foo'
Run Code Online (Sandbox Code Playgroud)

  • "*''Foo'需要成为班级名称.*" - 不!您可以轻松地从...导入`导入{Foo as Anything},因为您可以使用默认导出来导入任何来自...的东西. (2认同)
  • 您*可以*用“as”重命名它实际上并不是该源代码注释中的重点。感谢您的反对票;p (2认同)
  • 我没有反对,但是我不确定这个论点是否有说服力。我不知道在重构单个模块时我是否希望我的 IDE 重命名所有导入,这正是模块化的意义:-) 而且它似乎更像是一个 IDE“问题”,而不是选择导出样式的理由… (2认同)
  • 我同意我在这里使用命名导出是为了开发人员的用户体验——但是,你可能会争辩说 Typescript 本身就是关于这一点的。我经常重构,并且考虑到我通常每个文件有一个类(在我的情况下:React Component),我绝对希望导入遵循重命名的组件,而不是创建断开连接。当然,这可能有意义,也可能没有意义,具体取决于个人开发人员。 (2认同)

You*_* Lu 8

更重要的区别是:export default出口值,而export const/ export var/export let出口引用(被称为活的结合)。在 nodejs 中尝试以下代码(使用 13 或更高版本默认启用 es 模块):

// a.mjs

export let x = 5;
// or
// let x = 5;
// export { x }

setInterval(() => {
  x++;
}, 1000);

export default x;
Run Code Online (Sandbox Code Playgroud)
// index.mjs
import y, { x } from './1.mjs';

setInterval(() => {
  console.log(y, x);
}, 1000);
Run Code Online (Sandbox Code Playgroud)
# install node 13 or above
node ./index.mjs
Run Code Online (Sandbox Code Playgroud)

我们应该得到以下输出:

6 5
7 5
8 5
...
...
Run Code Online (Sandbox Code Playgroud)

为什么我们需要这种差异

最有可能的是,export default用于 commonjs 的兼容性module.exports

如何使用 bundler(rollup, webpack) 实现这一点

对于上面的代码,我们使用 rollup 来捆绑。

6 5
7 5
8 5
...
...
Run Code Online (Sandbox Code Playgroud)

和构建输出:

// build/index.js

let x = 5;
// or
// let x = 5;
// export { x }

setInterval(() => {
  x++;
}, 1000);

var y = x;

setInterval(() => {
  console.log(y, x);
}, 1000);

Run Code Online (Sandbox Code Playgroud)

请注意var y = x声明,即default.

webpack 有类似的构建输出。当大量模块加入构建时,文本拼接是不可持续的,打包器会用它Object.defineProperty来实现绑定(或者在 webpack 中称为和谐导出)。请在以下代码中找到详细信息:

rollup ./index.mjs --dir build 
Run Code Online (Sandbox Code Playgroud)
// build/index.js

let x = 5;
// or
// let x = 5;
// export { x }

setInterval(() => {
  x++;
}, 1000);

var y = x;

setInterval(() => {
  console.log(y, x);
}, 1000);

Run Code Online (Sandbox Code Playgroud)

请找出/* harmony export (binding) */和之间的不同行为/* harmony default export */

ES 模块原生实现

Mozilla 的es-modules-a-cartoon-deep-dive讲述了 es 模块的原因、内容和方式。


Jam*_*ers 5

文档:

命名导出对于导出多个值很有用.在导入期间,可以使用相同的名称来引用相应的值.

关于默认导出,每个模块只有一个默认导出.默认导出可以是函数,类,对象或任何其他内容.此值将被视为"主要"导出值,因为它将是最简单的导入值.


Abd*_*yal 5

当您设置默认值时,称为默认导出。每个文件只能有一个默认导出,并且可以使用您想要的任何名称将其导入到另一个文件中。当您不放置默认值时,它称为命名导出,您必须使用相同的名称将其导入到另一个文件中,并在其中包含大括号。