简体   繁体   English

ES6 中的 `export const` 与 `export default`

[英]`export const` vs. `export default` in ES6

I am trying to determine if there are any big differences between these two, other than being able to import with export default by just doing:我试图确定这两者之间是否有任何重大差异,除了能够通过执行以下操作以export default导入:

import myItem from 'myItem';

And using export const I can do:并使用export const我可以做到:

import { myItem } from 'myItem';

Are there any differences and/or use cases other than this?除此之外还有什么不同和/或用例吗?

It's a named export vs a default export.这是命名导出与默认导出。 export const is a named export that exports a const declaration or declarations. export const是一个命名的导出,它导出一个或多个 const 声明。

To emphasize: what matters here is the export keyword as const is used to declare a const declaration or declarations.强调一下:这里重要的是export关键字,因为const用于声明一个或多个 const 声明。 export may also be applied to other declarations such as class or function declarations. export也可以应用于其他声明,例如类或函数声明。

Default Export ( export default )默认导出( export default

You can have one default export per file.每个文件可以有一个默认导出。 When you import you have to specify a name and import like so:当您导入时,您必须指定一个名称并像这样导入:

import MyDefaultExport from "./MyFileWithADefaultExport";

You can give this any name you like.你可以给它任何你喜欢的名字。

Named Export ( export )命名导出( export

With named exports, you can have multiple named exports per file.使用命名导出,每个文件可以有多个命名导出。 Then import the specific exports you want surrounded in braces:然后导入您想要用大括号括起来的特定导出:

// 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

Or it's possible to use a default along with named imports in the same statement:或者可以在同一语句中使用默认值和命名导入:

import MyDefaultExport, { MyClass, MyOtherClass} from "./MyClass";

Namespace Import命名空间导入

It's also possible to import everything from the file on an object:也可以从对象的文件中导入所有内容:

import * as MyClasses from "./MyClass";
// use MyClasses.MyClass, MyClasses.MyOtherClass and MyClasses.default here

Notes笔记

  • The syntax favours default exports as slightly more concise because their use case is more common ( See the discussion here ).语法倾向于默认导出稍微更简洁,因为它们的用例更常见(请参阅此处的讨论)。
  • A default export is actually a named export with the name default so you are able to import it with a named import:默认导出实际上是一个名为default的命名导出,因此您可以使用命名导入来导入它:

     import { default as MyDefaultExport } from "./MyFileWithADefaultExport";

export default affects the syntax when importing the exported "thing", when allowing to import, whatever has been exported, by choosing the name in the import itself, no matter what was the name when it was exported, simply because it's marked as the "default". export default会影响导入导出的“事物”时的语法,当允许导入时,无论已导出什么,通过在import本身中选择名称,无论导出时的名称是什么,仅仅是因为它被标记为“默认”。

A useful use case, which I like (and use), is allowing to export an anonymous function without explicitly having to name it, and only when that function is imported, it must be given a name:一个我喜欢(并使用)的有用用例是允许导出匿名函数而无需显式命名它,并且只有在导入该函数时,才必须为其命名:


Example: 例子:

Export 2 functions, one is default :导出 2 个函数,一个是default的:

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;
}

Import the above functions.导入上述函数。 Making up a name for the default one:default名称命名:

// 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

When the {} syntax is used to import a function (or variable) it means that whatever is imported was already named when exported, so one must import it by the exact same name, or else the import wouldn't work.{}语法用于导入函数(或变量)时,这意味着导入的任何内容在导出时都已命名,因此必须以完全相同的名称导入它,否则导入将不起作用。


Erroneous Examples:错误示例:

  1. The default function must be first to import默认函数必须先导入

    import {divide}, square from './module_1.js
  2. divide_1 was not exported in module_1.js , thus nothing will be imported divide_1未在module_1.js中导出,因此不会导入任何内容

    import {divide_1} from './module_1.js
  3. square was not exported in module_1.js , because {} tells the engine to explicitly search for named exports only. square未在module_1.js中导出,因为{}告诉引擎仅显式搜索命名导出。

     import {square} from './module_1.js

More important difference is: export default exports value, while export const / export var / export let exports reference(or been called live binding).更重要的区别是: export default导出值,而export const / export var / export let导出引用(或称为实时绑定)。 Try below code in nodejs(using version 13 or above to enable es module by default):在 nodejs 中尝试以下代码(使用 13 或更高版本默认启用 es 模块):

// a.mjs

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

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

export default x;
// index.mjs
import y, { x } from './1.mjs';

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

And we should get below output:我们应该得到以下输出:

6 5
7 5
8 5
...
...

Why we need this difference为什么我们需要这种差异

Most probably, export default is used for compatibility of commonjs module.exports .很可能, export default用于 commonjs module.exports的兼容性。

How to achieve this with bundler(rollup, webpack)如何使用 bundler(rollup, webpack) 实现这一点

For above code, we use rollup to bundle.对于上面的代码,我们使用汇总来捆绑。

rollup ./index.mjs --dir build 

And the build output:和构建输出:

// build/index.js

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

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

var y = x;

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

Please pay attention to var y = x statement, which is the default .请注意var y = x语句,这是default的。

webpack has similar build output. webpack 有类似的构建输出。 When large scale of modules are added to build, concatenateing text is not sustainable, and bundlers will use Object.defineProperty to achieve binding(or called harmony exports in webpack).当添加大量模块构建时,拼接文本是不可持续的,bundlers 将使用Object.defineProperty来实现绑定(或在 webpack 中称为和谐导出)。 Please find detail in below code:请在下面的代码中找到详细信息:

main.js
...
/******/    // define getter function for harmony exports
/******/    __webpack_require__.d = function(exports, name, getter) {
/******/        if(!__webpack_require__.o(exports, name)) {
/******/            Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/        }
/******/    };
...
// 1.js
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[1],[
/* 0 */,
/* 1 */
/***/ (function(__webpack_module__, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "x", function() { return x; });
let x = 5;
// or
// let x = 5;
// export { x }

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

/* harmony default export */ __webpack_exports__["default"] = (x);


/***/ })
]]);

Please find the difference behavior between /* harmony export (binding) */ and /* harmony default export */ .请找出/* harmony export (binding) *//* harmony default export */之间的区别行为。

ES Module native implementation ES Module 原生实现

es-modules-a-cartoon-deep-dive by Mozilla told why, what and how about es module. Mozilla 的 es-modules-a-cartoon-deep-dive讲述了 es 模块的原因、内容和方式。

Minor note: Please consider that when you import from a default export, the naming is completely independent.次要注意:请考虑从默认导出导入时,命名是完全独立的。 This actually has an impact on refactorings.这实际上对重构有影响。

Let's say you have a class Foo like this with a corresponding import:假设您有一个像这样的类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'

Now if you refactor your Foo class to be Bar and also rename the file, most IDEs will NOT touch your import.现在,如果您将Foo类重构为Bar并重命名文件,大多数 IDE 将不会触及您的导入。 So you will end up with this:所以你最终会得到这个:

export default class Bar { }

// The name 'Foo' could be anything, since it's just an
// Identifier for the default export.
import Foo from './Bar'

Especially in TypeScript, I really appreciate named exports and the more reliable refactoring.特别是在 TypeScript 中,我非常欣赏命名导出和更可靠的重构。 The difference is just the lack of the default keyword and the curly braces.区别只是缺少default关键字和花括号。 This btw also prevents you from making a typo in your import since you have type checking now.顺便说一句,由于您现在进行了类型检查,因此还可以防止您在导入时出现拼写错误。

export class Foo { }

//'Foo' needs to be the class name. The import will be refactored
//in case of a rename!
import { Foo } from './Foo'

From the documentation :文档中

Named exports are useful to export several values.命名导出对于导出多个值很有用。 During the import, one will be able to use the same name to refer to the corresponding value.在导入期间,可以使用相同的名称来引用相应的值。

Concerning the default export, there is only a single default export per module.关于默认导出,每个模块只有一个默认导出。 A default export can be a function, a class, an object or anything else.默认导出可以是函数、类、对象或其他任何东西。 This value is to be considered as the "main" exported value since it will be the simplest to import.该值将被视为“主要”导出值,因为它将是最简单的导入值。

When you put default, its called default export.当您设置默认值时,它称为默认导出。 You can only have one default export per file and you can import it in another file with any name you want.每个文件只能有一个默认导出,并且可以将其导入到另一个文件中,使用任何您想要的名称。 When you don't put default, its called named export, you have to import it in another file using the same name with curly braces inside it.当您不设置默认值时,它称为命名导出,您必须将其导入到另一个文件中,使用相同的名称并在其中包含花括号。

I had the problem that the browser doesn't use ES6<\/a> .我遇到了浏览器不使用ES6<\/a>的问题。

I have fix it with:我已经修复它:

 <script type="module" src="index.js"></script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM