【问题标题】:Is there a difference between `export default x` and `export {x as default}`?`export default x` 和 `export {x as default}` 之间有区别吗?
【发布时间】:2017-01-09 15:18:29
【问题描述】:

我知道,对于 ES6 模块导出,导出的内容和导入的内容之间会发生绑定,因此当导出的变量发生变化时,导入的变量会显示该变化。

不过,我还了解到,在某些情况下,导入的变量只会绑定到导出的变量。

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

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

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

【问题讨论】:

标签: javascript ecmascript-6 es6-modules


【解决方案1】:

在一般情况下它们并不相同,尽管它们在函数和类的情况下可以表现相同。

let a = 4;
export default a;

等价于

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

意思是

let a = 4;
export default a;

a = 5;

将保留4 作为导出值,即使模块内的a 已更改,而export {a as default}; 将使导出值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* 是否会导致任何实际差异(导入时、实时只读视图等)?
  • 你是对的,添加了一个例子来说明为什么这种差异很重要。
【解决方案2】:

如中所述:

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

但没有关于性能差异的规范。

【讨论】:

  • 我认为 OP 不是在询问命名导出的语法,而是特别是 export default Xexport {X as default};
猜你喜欢
  • 2016-01-14
  • 2018-11-29
  • 2016-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多