' export const '和。' export default '在ES6中

我试图确定这两者之间是否有任何很大的区别,除了能够通过执行以下操作导入export default之外:

import myItem from 'myItem';

并且使用export const我可以做到:

import { myItem } from 'myItem';

除了这些,还有什么不同和/或用例吗?

210102 次浏览

的文档:

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

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

它是命名导出与默认导出的对比。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

笔记

  • 语法更倾向于默认导出,因为它们的用例更常见(参见此处的讨论)。
  • 默认导出实际上是一个名为default的命名导出,所以你可以用命名导入来导入它:

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

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

假设你有一个类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关键字和花括号。顺便说一句,这也可以防止您在导入中输入错误,因为您现在有类型检查。

export class Foo { }


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

当你输入default时,它被称为default export。每个文件只能有一个默认导出,并且可以使用任何名称将其导入到另一个文件中。当你不放default时,它叫做named export,你必须在另一个文件中导入它,使用相同的名字,里面有花括号。

export default在导入导出的“thing”时影响语法,当允许导入任何已导出的东西时,通过选择import本身中的名称,无论导出时的名称是什么,只是因为它被标记为“默认”。

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


<一个href = " https://rollupjs.org/repl?version=0.64.1&共享= JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMiUyRiolMjBUUkVFLVNIQUtJTkclMjAqJTJGJTVDbmltcG9ydCUyMGN1YmUlMkMlMjAlN0JkZXZpZGUlN0QlMjBmcm9tJTIwJy4lMkZtYXRocy5qcyclM0IlNUNuJTVDbmNvbnNvbGUubG9nKCUyMGN1YmUoJTIwMiUyMCklMkMlMjBkZXZpZGUoMiklMjApJTNCJTIwJTIyJTdEJTJDJTdCJTIybmFtZSUyMiUzQSUyMm1hdGhzLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMiUyRiUyRiUyMFRoaXMlMjBmdW5jdGlvbiUyMGdldHMlMjBpbmNsdWRlZCU1Q25leHBvcnQlMjBmdW5jdGlvbiUyMGRldmlkZSglMjB4JTIwKSU3QiU1Q24lNUN0cmV0dXJuJTIweCUyMCUyRiUyMDIlM0IlNUNuJTdEJTVDbiU1Q25leHBvcnQlMjBkZWZhdWx0JTIwZnVuY3Rpb24oJTIweCUyMCklN0IlNUNuJTVDdHJldHVybiUyMHglMjAqJTIwMiUzQiU1Q24lN0QlMjIlN0QlNUQlMkMlMjJvcHRpb25zJTIyJTNBJTdCJTIyZm9ybWF0JTIyJTNBJTIyZXMlMjIlMkMlMjJuYW1lJTIyJTNBJTIybXlCdW5kbGUlMjIlMkMlMjJnbG9iYWxzJTIyJTNBJTdCJTdEJTJDJTIyYW1kJTIyJTNBJTdCJTIyaWQlMjIlM0ElMjIlMjIlN0QlN0QlMkMlMjJleGFtcGxlJTIyJTNBbnVsbCU3RA = = noreferrer“rel = >例子:< / >

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

导入上述函数。为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

{}语法用于导入函数(或变量)时,这意味着无论导入的是什么,在导出时都以已经命名,因此必须以确切的相同的名称导入它,否则导入将无法工作。


错误的例子:

  1. 默认函数必须是第一个导入

    import {divide}, square from './module_1.js
    
  2. divide_1 was not exported in module_1.js, thus nothing will be imported

    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.

    import {square} from './module_1.js
    

更重要的是的区别是: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

如何使用捆绑器(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. c。

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 Module本地实现

es-modules-a-cartoon-deep-dive由Mozilla告诉为什么,什么和如何es模块。