我试图确定这两者之间是否有任何很大的区别,除了能够导入导出默认只做:
import myItem from 'myItem';
使用export const我可以做到:
import { myItem } from 'myItem';
除了这些,还有什么不同和/或用例吗?
我试图确定这两者之间是否有任何很大的区别,除了能够导入导出默认只做:
import myItem from 'myItem';
使用export const我可以做到:
import { myItem } from 'myItem';
除了这些,还有什么不同和/或用例吗?
当前回答
Export default在导入导出的thing时影响语法,当允许导入任何已导出的东西时,通过选择导入本身的名称,不管导出时的名称是什么,因为它被标记为“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;
}
导入上述函数。为默认名称创建一个名称:
// 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
当使用{}语法导入一个函数(或变量)时,这意味着导入的任何东西在导出时都已经命名,因此必须以完全相同的名称导入它,否则导入将无法工作。
错误的例子:
必须首先导入默认函数 从'./module_1.js导入{divide}, square module_1.js中没有导出Divide_1,因此不会导入任何东西 从'./module_1.js导入{divide_1} 在module_1.js中没有导出Square,因为{}告诉引擎显式地只搜索命名的导出。 从'./module_1.js导入{square}
其他回答
Export default在导入导出的thing时影响语法,当允许导入任何已导出的东西时,通过选择导入本身的名称,不管导出时的名称是什么,因为它被标记为“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;
}
导入上述函数。为默认名称创建一个名称:
// 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
当使用{}语法导入一个函数(或变量)时,这意味着导入的任何东西在导出时都已经命名,因此必须以完全相同的名称导入它,否则导入将无法工作。
错误的例子:
必须首先导入默认函数 从'./module_1.js导入{divide}, square module_1.js中没有导出Divide_1,因此不会导入任何东西 从'./module_1.js导入{divide_1} 在module_1.js中没有导出Square,因为{}告诉引擎显式地只搜索命名的导出。 从'./module_1.js导入{square}
更重要的区别是:export默认导出值,而export const/export var/export允许导出引用(或称为动态绑定)。尝试以下代码在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语句,这是默认值。
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本地实现
Mozilla的es-modules-a-cartoon-deep-dive讲述了es模块的原因、内容和方式。
注意:请考虑从默认导出导入时,命名是完全独立的。这实际上对重构有影响。
假设你有一个这样的类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,你必须在另一个文件中导入它,使用相同的名字,里面有花括号。