你的问题有点复杂,但我会尽力解释一切。
让我们首先确定模块的一般工作方式。模块有一组导出的名称,每个名称都引用该模块中的一个局部变量。导出的名称不需要与本地绑定的名称相同。导出的名称之一可以是default
,有专门用于模块仅导出单个内容的情况的特殊语法(导出和导入)。
我读到导入已被提升,但我不太确定这在这种情况下意味着什么:
import { foo } from 'my_module';
是的,进口报关单已悬挂。类似于var
or function
(实际上喜欢所有其他声明 https://stackoverflow.com/a/31222689/1048572) 标识符foo
在执行模块中的任何语句之前,从一开始就可用。事实上,绑定甚至是在声明的绑定之前创建的var
iables.
区别在于它们的初始化方式:
-
var
s 初始化为undefined
-
function
s and function*
s 用函数对象初始化
-
let
, const
and class
es 未初始化
-
导入绑定甚至没有真正初始化,它们被创建为指向导出名称在导入模块中引用的局部变量的指针
-
导入模块 (
import * as …
)用模块对象初始化(其属性也是这样的指针)
When is foo
设置为引用我的导出函数?
简短的回答:首先。
长答案:还没有真正确定。它是对导入模块中您希望保存该函数的局部变量的引用。当局部变量不存在时,它可能会改变const
- 但我们通常不希望这样。通常它确实已经包含该功能,因为导入的模块之前已被完全评估导入它的模块是。所以如果你担心有问题var functionName = function() {} vs function functionName() {} https://stackoverflow.com/q/336859/1048572你可能会松一口气——没有。
现在回到你的标题问题:
ES6 模块中导出函数表达式和函数声明有什么区别?
没什么特别的,这两个方面实际上没有太大关系:
-
export
声明将导出名称链接到模块范围内的局部变量
- 像往常一样,模块范围内的所有变量都会被提升
- 函数声明的初始化方式与通过函数表达式赋值的变量声明不同,as usual https://stackoverflow.com/q/336859/1048572
当然,仍然没有充分的理由不使用更多陈述性的函数声明无处不在;这在 ES6 模块中与以前没有什么不同。如果有的话,使用函数表达式的理由甚至可能更少,因为声明涵盖了所有内容:
/* for named exports */
export function foo() {…}
// or
function foo() {…}
export {foo as foo}
/* for default exports */
export default function foo() {…}
// or
function foo() {…}
export {foo as default}
// or
function foo() {…}
export default foo;
// or
export default function() {…}
好的,最后两个默认导出声明实际上与前两个有点不同。链接到导出名称的本地标识符default
is not foo
, but *default*
- 不能重新分配。这在最后一种情况下是有意义的(没有名字foo
),但在倒数第二个例子中你应该注意到foo
实际上只是一个本地别名,而不是导出的变量本身。我建议不要使用这种模式。
哦,在你问之前:是的,最后一个默认导出实际上也是一个函数声明,而不是一个表达式。一个匿名函数声明。这是 ES6 的新功能:-)
那么到底有什么区别export default function () {}
and 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!");
}
import def from "myself";
def(); // throws a TypeError about `def` not being a function
export default (function() {
console.log("I tried!");
});
无论如何,你真的不应该做这两件事。如果您想在模块中使用导出函数,请在其声明中为其指定名称。
既然如此,为什么要同时使用这两种语法呢?
发生。它是allowed通过规范,因为它没有制定额外的例外来禁止某些无意义的事情。这是不打算要使用的。在这种情况下,规范甚至明确不允许function
and class
中的表达式export default
语句并将它们视为声明。通过使用分组运算符,您发现了一个漏洞。做得好。不要滥用它。