从ES6模块导入函数表达式或函数声明有什么区别?

c10*_*b10 9 javascript ecmascript-6 es6-modules

据我所知(参见16.3.2.1节),ES6允许函数/类导出操作数的不同语法.差异是指导出的函数是否需要在导入时解释为函数声明,在这种情况下,您可以编写:export default function () {} // (a)或作为函数表达式:export default (function () {}); // (b).

作为一个可能的相关旁注:我读到进口是悬挂的,但我不确定这意味着什么.

以这个例子为例:

import foo from 'my_module'; // (c)

据我了解,上面的语句将我的导出函数保存在foo变量中.这个变量是悬挂的,或是什么,何时?

最重要的是,foomy_module使用函数(a)和使用函数导出时,有什么区别(在设置方面)(b)

Ber*_*rgi 14

你的问题有点令人费解,但我会尽力解释一切.

让我们首先确定模块的工作原理.模块具有一组导出的名称,每个名称都引用该模块中的局部变量.导出的名称不必与本地绑定的名称相同.其中一个导出的名称可以default是特殊语法(在导出和导入时),专用于模块仅导出单个内容的情况.

我读到进口已经悬挂,但我不确定这意味着什么:

import { foo } from 'my_module';
Run Code Online (Sandbox Code Playgroud)

是的,进口申报是悬挂的.与a varfunction(实际上与所有其他声明一样)类似foo,在执行模块中的任何语句之前,标识符从一开始就可用.实际上,绑定甚至是在声明的variable 之前创建的.

不同之处在于它们的初始化方式:

  • vars初始化为 undefined
  • functions和function*s用函数对象初始化
  • let,constclassES留下未初始化
  • 导入的绑定甚至没有真正初始化,它们被创建为指向导出的名称在导入的模块中引用的局部变量的指针
  • 导入的模块(import * as …)用模块对象初始化(其属性也是这样的指针)

何时foo设置为引用我的导出功能?

简短的回答:在其他一切之前.

答案很长:它没有真正确定.它是对您希望保留该函数的导入模块中的局部变量的引用.当局部变量没有变化时可能会发生变化const- 但我们通常并不期望这样.通常它确实包含该函数,因为导入的模块在导入它的模块之前被完全评估.因此,如果你担心var functionName = function(){} vs function functionName(){}有问题,你可能会感到宽慰 - 没有.

现在回到标题问题:

在ES6模块中导出函数表达式和函数声明有什么区别?

没什么特别的,这两个方面实际上没有多少关系:

  • export 声明将导出名称链接到模块范围中的局部变量
  • 像往常一样,模块范围内的所有变量都会被提升
  • 往常一样,函数声明的初始化方式与带有函数表达式赋值的变量声明的初始化方式不同

当然,没有充分的理由不在任何地方使用更多的声明性函数声明; 这与ES6模块没有什么不同.如果有的话,甚至可能没有理由使用函数表达式,因为声明涵盖了所有内容:

/* for named exports */
export function foo() {…}

// or
function foo() {…}
export {foo as foo}
Run Code Online (Sandbox Code Playgroud)

/* for default exports */
export default function foo() {…}

// or
function foo() {…}
export {foo as default}

// or
function foo() {…}
export default foo;

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

好的,最后两个默认导出声明实际上与前两个略有不同.链接到导出名称的本地标识符default不是foo,但是*default*- 它不能重新分配.这在最后一种情况下(没有名称foo)是有意义的,但在倒数第二种情况下,您应该注意到它foo实际上只是一个本地别名,而不是导出的变量本身.我建议不要使用这种模式.

哦,在你问之前:是的,最后的默认导出确实也是一个函数声明,而不是表达式.一个匿名函数声明.这是ES6的新功能:-)

那么export default function () {}和之间究竟有什么区别呢export default (function () {});

它们几乎可以用于各种目的.它们是具有.name属性的匿名函数,"default"由特殊*default*绑定保存,导出的名称default指向匿名导出值.
它们唯一的区别是提升 - 声明将在模块的顶部实例化它的函数,只有在模块代码的执行到达语句时才会计算表达式.但是,鉴于没有变量具有可访问的名称,除了一个非常奇怪的特殊情况外,这种行为是不可观察的:一个导入自身的模块.嗯,是的

import def from "myself";
def(); // works and logs the message
export default function() {
    console.log("I did it!");
}
Run Code Online (Sandbox Code Playgroud)

import def from "myself";
def(); // throws a TypeError about `def` not being a function
export default (function() {
    console.log("I tried!");
});
Run Code Online (Sandbox Code Playgroud)

无论如何,你真的不应该做这些事情.如果要在模块中使用导出的函数,请在其声明中为其指定名称.

在那种情况下,为什么有这两种语法?

发生.这是规范所允许的,因为它没有额外的例外来禁止某些荒谬的事情.它不打算使用.在这种情况下,规范甚至在语句中明确地禁止functionclass表达export default,并将它们视为声明.通过使用分组运算符,您发现了一个漏洞.做得好.不要滥用它.

  • 希望我的编辑能够回答您的问题:-) (2认同)