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

时间:2015-11-09 14:53:30

标签: javascript ecmascript-6 es6-modules

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

import myItem from 'myItem';

使用export const我可以这样做:

import { myItem } from 'myItem';

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

6 个答案:

答案 0 :(得分:255)

这是一个命名导出与默认导出。 export const是一个命名导出,用于导出const声明。

要强调:这里重要的是export关键字,因为const用于声明const声明或声明。 export也可以应用于其他声明,例如类或函数声明。

默认导出(export default

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

import MyDefaultExport from "./MyFileWithADefaultExport";

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

命名导出(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

或者可以在同一语句中使用默认值和命名导入:

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

命名空间导入

也可以从对象上的文件中导入所有内容:

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

备注

  • 语法偏好默认导出更简洁,因为它们的用例更常见(See the discussion here)。
  • 默认导出实际上是名为default的命名导出,因此您可以使用命名导入导入它:

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

答案 1 :(得分:12)

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

我喜欢(和使用)的一个有用的用例是,允许导出匿名函数,而无需明确地对其进行命名,并且仅当该函数为导入,必须为其指定名称:


Example:

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

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

使用{}语法导入函数(或变量)时,这意味着导入的任何内容在导出时均已 命名,因此必须使用进行导入完全相同的名称,否则导入将无效。


错误示例:

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

    import {divide}, square from './module_1.js
    
  2. divide_1未在module_1.js中导出,因此不会导入任何内容

    import {divide_1} from './module_1.js
    
  3. square未在module_1.js中导出,因为{}告诉引擎仅明确搜索命名导出。

    import {square} from './module_1.js
    

答案 2 :(得分:7)

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

假设您有一个类似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'

现在,如果您将Foo类重构为Bar并重命名该文件,则大多数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'

特别是在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'

答案 3 :(得分:5)

来自the documentation

  

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

     

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

答案 4 :(得分:4)

更重要的区别在于: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;
// index.mjs
import y, { x } from './1.mjs';

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

我们应该得到以下输出:

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

为什么我们需要这种差异

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

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

对于上面的代码,我们使用 rollup 来打包。

rollup ./index.mjs --dir build 

和构建输出:

// build/index.js

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

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

var y = x;

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

<块引用>

请注意var y = x语句,即default

<块引用>

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

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


/***/ })
]]);
<块引用>

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

ES 模块原生实现

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

答案 5 :(得分:0)

当你输入默认值时,它被称为默认导出。每个文件只能有一个默认导出,您可以将其导入到您想要的任何名称的另一个文件中。如果您没有设置默认值,即名为“导出”,则必须使用相同的名称将其导入另一个文件中,并在其中包含花括号。