【问题标题】:Why Is `Export Default Const` invalid?为什么“导出默认常量”无效?
【发布时间】:2016-07-15 15:30:55
【问题描述】:

我看到以下内容很好:

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

但是,这是不正确的:

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

但这很好:

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

能否解释一下为什么constexport default 无效?这是不必要的添加吗?任何声明为export default 的东西都被假定为const 或类似的东西?

【问题讨论】:

  • export default Tab = connect( mapState, mapDispatch )( Tabs ); 应该是 export default connect( mapState, mapDispatch )( Tabs );。您正在导出函数调用的结果,而不是变量 Tab。
  • 一个 const 或 let 在导出模块中是必需的(并且相关),但在导入模块中无关紧要,其中导入的标识符始终是只读的(不能分配给)。这仍然不能解释为什么“导出默认”的语法不同于非默认的“导出”。
  • 注意:export default Tab = 是语法错误,Tab 未定义。这将是有效语法的唯一方法是,如果您之前通过 let 或 var 将 Tab 分配给某些东西......例如 let Tab; export default Tab = ... 这不是一个好习惯。
  • 这不是语法错误,分配给未定义的变量是有效的JS。但很可能是不受欢迎的行为。

标签: javascript scope export constants default


【解决方案1】:

const 就像 let, it is a LexicalDeclaration (VariableStatement, Declaration) 用于在你的块中定义一个标识符。

您正在尝试将其与 default 关键字、which expects a HoistableDeclaration, ClassDeclaration or AssignmentExpression 混合以跟随它。

因此它是一个SyntaxError


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

export 本身接受 VariableStatementDeclaration 在其右侧。


以下就可以了export default Tab;

Tab 成为一个 AssignmentExpression,因为它被赋予了名称 default ?

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

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


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

如果您试图从概念上理解这一点并且上面的规范推理没有帮助,请将其视为 “如果 default 是合法标识符而不是保留令牌,那么会有什么不同的方式写export default Foo;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's comment 而变得模棱两可,因此改为显式编写此模式更有意义。

【讨论】:

  • 答案是它是如何变成错误的。问题仍然是为什么?它以这种方式防止滥用 const 的一个原因:export default const a=1, b=3, c=4;
  • "AFAIK the export in itself should not add anything to your current scope" 这不太准确,因为export const a = 1a 添加到您当前的上下文中。即使在类的情况下使用export default,因为export default class MyClass {} 也会将MyClass 添加到您当前的上下文中。
  • @SergeyOrlov 同意这解释了它是如何产生错误的,但对于为什么它是必要的却没有说明什么。虽然我不确定这是唯一的原因,但您可能应该将其作为单独的答案发布,而不是对此发表评论。
  • 答案是另一个问题。原始问题没有答案。
  • 我支持@Pavel1114——这回答了为什么解析器将其作为语法错误拒绝,但没有解释为什么语法旨在防止export default const ...,尽管是非法的,但似乎完全有意义的构造。我非常怀疑@Kayote 是否在询问解析器。
【解决方案2】:

如果你想导出默认的 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>);

【讨论】:

  • 是的,那行得通——但感觉太错误了,我发现自己真希望你没有发布它。有人会将其复制并粘贴到他们的源代码中! ?
【解决方案3】:

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

import React from 'react'

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

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

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

import React from 'react'

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

【讨论】:

  • 您没有遇到堆栈跟踪问题吗?对我来说,这导致在未命名默认导出的任何地方显示Unknown
  • 虽然这行得通,但毫无疑问,玩具应用程序开发之外的每个 React 开发人员都应该不惜一切代价避免
  • @lix 我不明白为什么要避免使用这种语法。你能解释一下或分享一个链接吗?谢谢。
  • @sudip 创建一个没有名字的组件不利于react组件模型和渲染。
  • 看起来很干净,但 Dan Abramov 也建议我们应该在组件声明中使用正确的函数/常量名称:twitter.com/dan_abramov/status/1255229440860262400 ;) “- 将在堆栈跟踪中显示为匿名 - 将显示为未知在 DevTools 中 - 不会被特定于 React 的 lint 规则检查 - 不能与快速刷新等某些功能一起使用”
【解决方案4】:

Paul 分享的答案是最好的。要展开更多,

每个文件只能有一个默认导出。而可以有多个 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';。只是为了进一步澄清 - 只有命名的导出可以使用花括号 ({})。由于每个模块文件只能有一个默认导出,因此导入默认 var 并不像导入 message2 那样需要它们。
【解决方案5】:

Paul 的答案就是您要找的答案。但是,实际上,我认为您可能对我在自己的 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 )看起来更干净@

【讨论】:

  • 太糟糕的装饰器似乎不能用于功能组件
  • @EricKim Bummer。但是,值得记住的是,装饰规范还不是最终的。也许功能组件无法使用“遗留”装饰器进行装饰,但我不知道这是由于遗留设计的限制,还是因为遗留装饰器的实现不完整或有问题。 FWIW:@connect 是我唯一使用的装饰器,我只将它与附加到 redux 存储的组件一起使用,几乎每一个都是“路由”,并且几乎每个路由都应该有状态(因此不能是纯函数)。
【解决方案6】:

default 基本上就是const someVariableName

您不需要命名标识符,因为它是文件的默认导出,您可以在导入时随意命名,因此default 只是将变量赋值压缩为单个关键字。

【讨论】:

  • "default 基本上是const foo",不完全是,至少export default a = 1;a=2; 给出assignment to undeclared variable aexport const a = 1;a=2; 给出invalid assignment to const 'a'。此外,export default a = 1; 允许未命名(默认)导入和命名导入,而 export const a = 1; 仅允许命名导入。完全不准确的答案。
猜你喜欢
  • 2022-11-15
  • 2017-02-01
  • 1970-01-01
  • 2019-11-23
  • 2017-11-12
  • 1970-01-01
  • 2015-03-18
  • 1970-01-01
  • 2018-02-08
相关资源
最近更新 更多