从ES6模块导入函数表达式或函数声明有什么区别? [英] What is the difference between importing a function expression or a function declaration from a ES6 module?

查看:110
本文介绍了从ES6模块导入函数表达式或函数声明有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



作为一个可能的相关sidenote:我看到导入已经悬停,但我不知道那是什么在这种情况下的意思。



以下示例:



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



据了解,上述语句将会将导出的函数保存在 foo 变量。这个变量是挂起还是什么,什么时候?



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

解决方案

你的问题有点复杂但我会尽力解释一切。



我们首先建立模块的工作原理。一个模块有一组导出的名称,每个引用的名称都是该模块中的一个局部变量。导出的名称不需要与本地绑定的名称相同。其中一个导出的名称可以是 default ,其中有专门的语法(导出和导入),专门用于模块仅导出单个东西的情况。 p>


我看到导入已被吊起,但我并不确定这是什么意思在这种情况下:


$来自'my_module'的b $ b

  import {foo}; 


是的,导入声明已被吊起。类似于 var 函数(实际上像其他声明)标识符 foo 在模块中的任何语句执行之前从头开始。实际上,绑定甚至是在已声明的 var 之前创建的。



区别是它们是如何初始化的:




  • var 被初始化为 undefined

  • 函数 s和函数* 函数对象

  • let const 未进行初始化的类 es

  • 导入的绑定甚至没有初始化,它们被创建为指向本地变量的指针,导入的名称是指导入的模块

  • 导入的模块 import * as ... )初始化一个模块对象(其属性也是这样的指针)




什么时候是 foo 设置为引用我的导出功能


>

长安wer:没有真正设置它是引用您期望保存该功能的导入模块中的局部变量的引用。当它不是 const 时,局部变量可能会改变 - 但是我们通常不会指望当然。通常它确实包含该功能,因为导入的模块在导入模块之前已被完全评估。所以如果您担心 var functionName = function(){} vs function functionName(){} 有问题,您可能会解除 - 没有。



现在回到你的标题问题:


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


没有什么特别之处,与彼此有很多关系:




  • export 声明链接导出名称到模块范围中的局部变量

  • 模块范围中的所有变量都被吊起,像往常一样

  • 函数声明的初始化与变量声明不同,函数表达式的分配,一如既往



当然,还没有很好的理由不使用更多的 declarative 函数声明无处不在;这在ES6模块中并没有差异。如果有的话,使用函数表达式的原因可能更少,因为所有内容都被声明所覆盖:

  / * export * / 
export function foo(){...}

//或
function foo(){...}
export {foo as foo}

  / * for default export * / 
export default function foo(){...}

//或
function foo(){...}
export {foo as默认}

//或
function foo(){...}
export default foo;

//或
export default function(){...}

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



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


那么 export default function(){} / code>和 export default(function(){});




他们对于每一个目的都是一样的。它们是匿名函数,由$ .name 属性default $ c> * default *
绑定到导出名称默认值指向匿名导出值。

他们唯一差异是提升 - 声明将在模块的顶部实现其功能,表达式只有在模块代码的执行到达语句后才会被求值。然而,鉴于没有可变名称的变量,除了一个非常奇怪的特殊情况,这个行为是不可观察的:一个导入自身的模块。嗯,是的。

  import def frommyself; 
def(); //工作并记录消息
export default function(){
console.log(我做了!);
}

  import def frommyself; 
def(); //抛出一个TypeError关于`def`不是一个函数
export default(function(){
console.log(I try!);
});

你真的不应该这样做。如果要在模块中使用导出的函数,请在其声明中给出一个名称。


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


发生。该规范允许允许,因为它不会产生额外的例外来禁止某些无意义的事情。不要使用 。在这种情况下,规范甚至明确禁止导出默认值函数 class c $ c>语句,并将它们视为声明。通过使用分组操作符,您发现了一个漏洞。做得好。不要滥用它。


As I understand it (see section 16.3.2.1), ES6 allows different syntaxes for function / class export operands. The difference refers to whether the exported function needs to be interpreted at import as a function declaration, in which case you write: export default function () {} // (a) or as a function expression: export default (function () {}); // (b).

As a possible related sidenote: I read that imports are hoisted, but I'm not really sure what that means in this context.

Taking the case of this example:

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

As I understand it, the above statement will save my exported function in a foo variable. Is that variable hoisted, or what is, and when?

Most importantly, what is the difference (in terms of setting foo) when my_module exports the function using (a) and when it exports it using (b)?

解决方案

Your question is a bit convoluted but I'll try my best to explain everything.

Let's first establish how modules work in general. A module has a set of exported names, each of which refer to a local variable in that module. The name of the export does not need to be the same as that of the local binding. One of the exported names can be default, for which there is special syntax (both in exporting and importing) dedicated for the case that a module only exports a single thing.

I read that imports are hoisted, but I'm not really sure what that means in this context:

import { foo } from 'my_module';

Yes, import declarations are hoisted. Similarly to a var or function (and actually like every other declaration) the identifier foo is available right from the beginning, before any statements in the module are executed. In fact the binding is even created before those of declared variables.

The difference is how they are initialised:

  • vars are initialised with undefined
  • functions and function*s are initialised with the function object
  • let, const and classes are left uninitialised
  • imported bindings are not even really initialised, they are created as a pointer to the local variable that the exported name refers to in the imported module
  • imported modules (import * as …) are initialised with a module object (whose properties are such pointers as well)

When is foo set to refer to my exported function?

The short answer: before everything else.

The long answer: it's not really set. It's a reference to the local variable in the imported module that you expect to hold the function. The local variable might change when it's not const - but we usually don't expect that of course. And normally it does contain that function already, because the imported module is completely evaluated before the module(s) that import it are. So if you fear there's a problem with var functionName = function() {} vs function functionName() {} you may be relieved - there is not.

Now back to your title question:

What is the difference between exporting a function expression and a function declaration in a ES6 module?

Nothing special, the two aspects actually don't have much to do with each other:

  • export declarations link an export name to a local variable in the module scope
  • All variables in the module scope are hoisted, as usual
  • function declarations are initialised differently than variable declarations with an assignment of a function expression, as usual

Of course, there still are no good reasons not to use the more declarative function declarations everywhere; this is not different in ES6 modules than before. If at all, there might even be less reasons to use function expressions, as everything is covered by declarations:

/* 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() {…}

Ok, the last two default export declarations are actually a bit different than the first two. The local identifier that is linked to the exported name default is not foo, but *default* - it cannot be reassigned. This makes sense in the last case (where there is no name foo), but in the second-to-last case you should notice that foo is really just a local alias, not the exported variable itself. I would recommend against using this pattern.

Oh, and before you ask: Yes, that last default export really is a function declaration as well, not an expression. An anonymous function declaration. That's new with ES6 :-)

So what exactly is the difference between export default function () {} and export default (function () {});

They are pretty much the same for every purpose. They're anonymous functions, with a .name property "default", that are held by that special *default* binding to to which the exported name default points to for anonymous export values.
Their only difference is hoisting - the declaration will get its function instantiated at the top of the module, the expression will only be evaluated once the execution of module code reaches the statement. However, given that there is no variable with an accessible name for them, this behavior is not observable except for one very odd special case: a module that imports itself. Um, yeah.

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!");
});

You really shouldn't do either of these things anyway. If you want to use an exported function in your module, give it a name in its declaration.

In that case, why have both syntaxes?

Happens. It's allowed by the spec because it doesn't make extra exceptions to prohibit certain nonsensical things. It is not intended to be used. In this case the spec even explicitly disallows function and class expressions in export default statements and treats them as declarations instead. By using the grouping operator, you found a loophole. Well done. Don't abuse it.

这篇关于从ES6模块导入函数表达式或函数声明有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆