为什么“导出默认常量”无效?

IT技术 javascript scope export constants default
2021-03-07 22:02:43

我看到以下内容很好:

const Tab = connect( mapState, mapDispatch )( Tabs );
export default Tab;

然而,这是不正确的:

export default const Tab = connect( mapState, mapDispatch )( Tabs );

但这很好:

export default Tab = connect( mapState, mapDispatch )( Tabs );

可以解释一下为什么const无效export default吗?这是一个不必要的添加和任何声明为export default假定的东西const吗?

6个回答

const就像let它是一个LexicalDeclaration ( VariableStatement, Declaration ),用于在您的块中定义标识符。

您正在尝试将其与default关键字混合使用,该关键字期望紧随其后的HoistableDeclaration、ClassDeclarationAssignmentExpression

因此它是一个SyntaxError


如果你想要const一些东西,你需要提供标识符而不是使用default.

export本身接受其右侧VariableStatement声明


以下是好的export default Tab;

Tab成为AssignmentExpression因为它的名称是default ?

export default Tab = connect( mapState, mapDispatch )( Tabs ); 很好

Tab = connect( mapState, mapDispatch )( Tabs );是一个AssignmentExpression


更新:想象问题的不同方式

如果您试图从概念上理解这一点并且上面的规范推理没有帮助,请将其视为“如果default是合法标识符而不是保留令牌,那么编写export default Foo;and的不同方式是export default const Foo = 1;什么?”

在这种情况下,编写它的扩展方式将是

// pseudocode, this thought experiment is not valid JS

export default Foo;
// would be like
export const default = Foo;

export default const Foo = 1;
// would be like
export const default const Foo = 1;
// so would the following line make sense?
const bar const Foo = 1;

有一个有效的论点,扩展应该是这样的

// pseudocode, this thought experiment is not valid JS

export default const Foo = 1;
// would be like
const Foo = 1;
export const default = Foo;

但是,根据Sergey 的评论,这将变得模棱两可,因此明确地编写此模式更有意义。

答案是另一个问题。原始问题没有答案。
2021-04-21 22:02:43
"AFAIK the export in itself should not add anything to your current scope"这不是那么准确,因为export const a = 1增加a了您当前的上下文。即使export default在类的情况下,因为也会export default class MyClass {}添加MyClass到您当前的上下文中。
2021-04-26 22:02:43
我和@Pavel1114 在一起——这回答了为什么解析器拒绝它作为语法错误,但没有解释为什么语法被设计为 preventexport default const ...,尽管是非法的,但似乎很有意义。我非常怀疑@Kayote 是在询问解析器。
2021-05-01 22:02:43
@SergeyOrlov 同意这解释了这是如何产生错误的,但几乎没有说明为什么有必要。尽管我不确定这是唯一的原因,但您可能应该将其作为单独的答案发布,而不是对此发表评论。
2021-05-08 22:02:43
答案是它是如何变成错误的。问题仍然是为什么?以这种方式防止滥用 const 的一个原因:export default const a=1, b=3, c=4;
2021-05-10 22:02:43

如果你想导出默认的 const/let,你也可以做这样的事情,而不是

const MyComponent = ({ attr1, attr2 }) => (<p>Now Export On other Line</p>);
export default MyComponent

你可以做这样的事情,我个人不喜欢。

let MyComponent;
export default MyComponent = ({ }) => (<p>Now Export On SameLine</p>);
是的,那行得通——但感觉如此错误,以至于我发现自己希望你没有发布它。有人会把它复制并粘贴到他们的源代码中的某个地方!😬
2021-05-03 22:02:43

如果在文件名中解释了组件名称MyComponent.js,只需不要命名组件,保持代码精简。

import React from 'react'

export default (props) =>
    <div id='static-page-template'>
        {props.children}
    </div>

更新:由于这在堆栈跟踪中将其标记为未知,因此不推荐

更新 2:我只使用了下面的 es5 版本,因为它在堆栈跟踪和react开发工具上保留了名称。

import React from 'react'

export default function MyComponent(props) {
    return (<div id='static-page-template'>
        {props.children}
    </div>)
}
@lix 我不明白为什么应该避免使用这种语法。你能解释一下或分享一个链接吗?谢谢。
2021-04-26 22:02:43
@sudip 创建一个没有名字的组件对反应组件模型和渲染不利。
2021-04-28 22:02:43
你没有堆栈跟踪问题吗?对我来说,它导致Unknown在未命名默认导出的任何地方显示
2021-04-29 22:02:43
但是看起来很干净,Dan Abramov 也建议我们应该在组件声明中使用正确的函数/常量名称:twitter.com/dan_abramov/status/1255229440860262400 ;) "- 将在堆栈跟踪中显示为 Anonymous - 将在 DevTools 中显示为 Unknown - 不会被 React 特定的 lint 规则检查 - 不适用于某些功能,例如快速刷新”
2021-05-12 22:02:43
虽然这是可行的,但毫无疑问,这是玩具应用程序开发之外的每个 React 开发人员都应该不惜一切代价努力避免的事情。
2021-05-15 22:02:43

保罗分享的答案是最好的。为了扩大,

每个文件只能有一个默认导出。而可以有多个 const 导出。默认变量可以使用任何名称导入,而 const 变量可以使用其特定名称导入。

var message2 = 'I am exported';
export default message2;
export const message = 'I am also exported'

在导入端,我们需要像这样导入它:

import { message } from './test';

或者

import message from './test';

第一次导入时,会导入 const 变量,而第二次导入时,将导入默认变量。

不确定这是否是一个错字,但默认导出变量是message2,所以它应该是import message2 from './test';. 只是为了进一步澄清 - 只有命名的导出才能使用花括号 ({})。由于每个module文件只能有一个默认导出,因此导入默认变量不需要它们,如导入message2.
2021-05-12 22:02:43

保罗的答案就是您正在寻找的答案。但是,作为一个实际问题,我认为您可能对我在自己的 React+Redux 应用程序中使用的模式感兴趣。

这是我的一个路由中的一个精简示例,展示了如何定义组件并使用单个语句将其导出为默认值:

import React from 'react';
import { connect } from 'react-redux';

@connect((state, props) => ({
    appVersion: state.appVersion
    // other scene props, calculated from app state & route props
}))
export default class SceneName extends React.Component { /* ... */ }

(注意:我使用术语“场景”来表示任何路由的顶级组件)。

我希望这是有帮助的。我认为它看起来比传统的要干净得多connect( mapState, mapDispatch )( BareComponent )

太糟糕的装饰器似乎不能用于功能组件
2021-05-14 22:02:43
@EricKim 无赖。但是,值得记住的是,装饰器规范还不是最终版本。也许功能组件无法使用“遗留”装饰器进行装饰,但我不知道这是由于遗留设计的限制,还是因为遗留装饰器的实现不完整或有缺陷。FWIW:@connect是我唯一使用的装饰器,我只将它与附加到 redux 存储的组件一起使用,几乎每一个都是“路由”,并且几乎每个路由都应该有状态(因此不能是纯函数) .
2021-05-15 22:02:43