`export default x` 和 `export {x as default}` 有什么区别吗?(涉及IT技术)

10

我知道在 ES6 模块输出时,会进行导出和导入之间的绑定,这样当导出的变量发生改变时,导入的变量也会反映出这种变化。

然而,我也阅读过导入的变量只在特定情况下才携带到与导出变量之间的绑定关系。

我的具体问题是,在以下两种情况下,导出变量的绑定方式是否存在差异...

// Scenario #1
let a = 5;
export default a;

// Scenario #2
let a = 5;
export { a as default };

2个回答

11

总体来说,它们并不相同,但在函数和类的情况下它们可以表现得相同。

let a = 4;
export default a;

等同于

let a = 4;
let *default* = a;
export {*default* as default};

意味着

let a = 4;
export default a;

a = 5;
export {a};会导出值为a的变量,即使模块内部的a已经改变,输出的值仍然是4。而使用export {a as default};则会将a的值5作为默认输出。

ECMAScript 规范定义了三种不同形式的export default,在这个表格中给出了一些例子:http://www.ecma-international.org/ecma-262/7.0/#table-42,在主要语法声明中也有相关内容:http://www.ecma-international.org/ecma-262/7.0/#sec-exports

export default HoistableDeclaration
export default ClassDeclaration
export default [lookahead ∉ { function, class }] AssignmentExpression;
在这种情况下,HoistableDeclaration 映射到函数声明和生成器声明。
如果我们查看规范,在其中定义了从文件内变量名称到导出名称的映射,请参见http://www.ecma-international.org/ecma-262/7.0/#sec-exports-static-semantics-exportentries
ExportDeclaration: export default HoistableDeclaration
  Let names be BoundNames of HoistableDeclaration.
  Let localName be the sole element of names.
  Return a new List containing the Record {[[ModuleRequest]]: null,
    [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default"}.

ExportDeclaration: export default ClassDeclaration
  Let names be BoundNames of ClassDeclaration.
  Let localName be the sole element of names.
  Return a new List containing the Record {[[ModuleRequest]]: null,
    [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default"}.

ExportDeclaration: export default AssignmentExpression;
  Let entry be the Record {[[ModuleRequest]]: null, [[ImportName]]: null,
    [[LocalName]]: "*default*", [[ExportName]]: "default"}.
  Return a new List containing entry.

  NOTE
  "*default*" is used within this specification as a synthetic name for anonymous default export values.
在这里,BoundNames返回作为值传递的函数或类的名称,因此在前两种情况下
export default function fn(){}
// or 
export default function* fn(){}
// or
export default class cls {}

将为变量fncls导出活动绑定。

你也可以这样做

export default function(){}
// or 
export default function*(){}
// or
export default class {}

如果是这种情况,它们将导出没有名称的值而不是绑定。

export default AssignmentExpression ;的最后一种情况中,你的export default a;示例就属于这种情况。你可以注意到它有[[LocalName]]: *default*而不是像其他变量一样[[LocalName]]: localName。这是因为export default a;并不把a作为被导出名字,而是把a当前的值作为导出值进行处理。这与export default 4;没有什么不同,从规范的角度来看,它没有名称。

基本上

export default function fn(){}

等同于

function fn(){}
export {fn as default};

但是

let a = 4;
export default a;

并不等同于:

let a = 4;
export {a as default};

好的,“let a = 4; export default a” 等同于 “export default 4”。当导入、实时只读视图等方面,使用“[[LocalName]]: localName”/“[[LocalName]]: default”是否会产生任何实际差异? - user6445533
你是对的,我添加了一个示例来说明为什么这种差异很重要。 - loganfsmyth

0

如下所述:

Mozilla Docs

场景1

它用于命名导出

// module "my-module.js"
export function cube(x) {
  return x * x * x;
}
const foo = Math.PI + Math.SQRT2;
export { cube, foo };

场景2

它用于导出单个值或为模块提供备用值

// module "my-module.js"
export default function cube(x) {
  return x * x * x;
}

虽然没有关于性能差异的具体规定。


2
我认为OP并不是在询问命名导出的语法,而是具体指export default Xexport {X as default};之间的区别。 - loganfsmyth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接