`export default x`和`export {x as default}之间有区别吗?

sfl*_*che 8 javascript ecmascript-6 es6-modules

我理解,使用ES6模块导出时,导出的内容与导入的内容之间会发生绑定,因此当导出的变量发生更改时,导入的变量将演示该更改.

但是,我还读到导入的变量在某些情况下只携带绑定到导出的变量.

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

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

// Scenario #2
let a = 5;
export { a as default };
Run Code Online (Sandbox Code Playgroud)

log*_*yth 9

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

let a = 4;
export default a;
Run Code Online (Sandbox Code Playgroud)

相当于

let a = 4;
let *default* = a;
export {*default* as default};
Run Code Online (Sandbox Code Playgroud)

意思是

let a = 4;
export default a;

a = 5;
Run Code Online (Sandbox Code Playgroud)

将保留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;
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

BoundNames 这里返回作为值传递的函数或类的名称,因此在前两种情况下

export default function fn(){}
// or 
export default function* fn(){}
// or
export default class cls {}
Run Code Online (Sandbox Code Playgroud)

将导出变量的实时绑定fncls.

你也可以这样做

export default function(){}
// or 
export default function*(){}
// or
export default class {}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,这些将导出没有实时绑定的值,因为它们没有名称.

在最后一种情况下export default AssignmentExpression ;,这就是你export default a;满足的例子.你可以注意到它[[LocalName]]: *default*不是[[LocalName]]: localName喜欢其他的.这是因为export default a;无法识别a为正在导出的名称,它将其作为a导出值的当前值进行处理.这没有什么不同export default 4;,它从规范的角度来看没有名称.

实质上

export default function fn(){}
Run Code Online (Sandbox Code Playgroud)

相当于

function fn(){}
export {fn as default};
Run Code Online (Sandbox Code Playgroud)

let a = 4;
export default a;
Run Code Online (Sandbox Code Playgroud)

不等于:

let a = 4;
export {a as default};
Run Code Online (Sandbox Code Playgroud)