【问题标题】:What is the difference between with and without curly bracket notation in export/import statements?导出/导入语句中带和不带大括号符号的区别是什么?
【发布时间】:2017-10-05 00:18:07
【问题描述】:

我是 ES6 新手,对类的导出和导入方式有些困惑。似乎许多不同的符号是有效的,但工作方式不同。

我在src/web-api.js写了这样一个类:

class WebApi {
    // ...
}

export { WebApi };

我导入的是:

import { WebApi } from './src/web-api.js'

这很好用,但是在我尝试没有大括号的相同操作之前它没有用:

export WebApi; // Tells me '{' expected

import WebApi from './src/web-api.js'; // No syntax error but WebApi is undefined

即使在MDN documentation for export 上,符号export expression; 似乎也是有效的。

同样,这是在我的应用程序文件中导入 React 的方式:

import React, { Component } from 'react';

为什么一类有大括号,另一类没有大括号?一般来说,我如何判断何时使用和不使用大括号?

【问题讨论】:

标签: javascript import ecmascript-6 export


【解决方案1】:

大括号只是语法糖。它将使用变量名作为对象键,例如:

const a = 1;
const test = {a}; // same as {a: 1};

它也可以用来通过变量名来解构对象。它将检查对象是否具有与变量名称相同的值的任何属性,如果找到,则输出一个值:

const test = {a: 1};
const {a} = test; // a = 1

在模块中,一般用例是当你导入时通常会有大括号,因为模块被导入为MODULE.functionMODULE.class。先看出口会更直观:

对于导出,它使用我之前提到的语法糖 - 您将它作为对象导出。当你做export { WebApi }; 时,你真正在做的是export {WebApi: WebApi}。这使得访问事物变得更容易,因为您现在可以执行“MODULE.WebApi”来访问该类,而不是让它不必要地污染命名空间。这也是所有导出所必需的!

继续导入,您在导入语句中所做的实际上是解构模块对象并选择要保存到同名变量中的属性。在您的情况下,当您执行 import {WebApi} from './src/web-api.js' 时,您将执行类似 import WebApi = web-api.js['WebApi'] from './src/web-api.js' 的操作(这不是有效的语法,只是为了向您展示它在后台执行的操作)。这也是正确导入模块函数/类所必需的。也可以选择导入整个模块,就像 NodeJS 所做的那样:import * as ModuleName from './src/module.js'。这会将所有导出的函数/类放入 ModuleName 对象中,以便可以将其视为普通模块。

但是,如果模块具有default 导出,则导入和导出不需要大括号。例如,react 的文件中可能包含 export default React - 这就是为什么当您执行 import React from 'react' 时不需要大括号的原因

希望我没有太困惑,如果我能澄清任何事情,请告诉我!

【讨论】:

  • 对对象解构的引用不合适。 import 语法是自包含的,并试图模仿解构语法(到适用的程度)。它不是解构,它只是语法糖。
【解决方案2】:

ES6 提供了许多 方法来通过导入/导出来管理模块。但基本上有两种主要策略:

  1. 默认导出/导入 export defaultimport module from './module'
  2. 多个导出/导入 exportimport {member} from './module'import * as module from './module'

(可以混合使用,但不推荐。)


要导出/导入的模块

function foo() {
  console.log('Foo');
}

function bar() {
  console.log('Bar');
}

策略 #1:默认导出/导入

导出 (module.js)

function foo() {
  console.log('Foo');
}

function bar() {
  console.log('Bar');
}

export default {foo, bar};

/*
  {foo, bar} is just an ES6 object literal that could be written like so:

  export default {
    foo: foo,
    bar: bar
  };

  It is the legacy of the "Revealing Module pattern"...
*/

导入(main.js)

import module from './module';

module.foo(); // Foo
module.bar(); // Bar

策略 #2:多次导出/导入

导出 (module.js)

export function foo() {
  console.log('Foo');
}

export function bar() {
  console.log('Bar');
}

导入(main.js)

import {foo, bar} from './module';

foo(); // Foo
bar(); // Bar

/*
  This is valid too:

  import * as module from './module';

  module.foo(); // Foo
  module.bar(); // Bar
*/

正如我之前所说,ES6 模块比这复杂得多。有关更多信息,我建议您阅读 Dr. Exploring ES6。 Axel Rauschmayer,尤其是这一章:http://exploringjs.com/es6/ch_modules.html

【讨论】:

  • 非常感谢您的详细回答。 JS 社区是否对首选的导出策略有任何共识?
  • 我不这么认为。我会说多个命名导出提供了灵活性,而单个默认导出提供了稳定性。在 Node.js 应用程序(使用 CommonJS)中,单个导出的对象字面量非常流行(感谢 Revealing Module 模式...)。但老实说,这主要是一个偏好问题。使用一个或另一个。只是避免在同一个模块中使用两者,出于同样的原因,您应该避免将蛇盒与骆驼盒混合使用。这是可能的,但不一致。
【解决方案3】:

在您的情况下,如果您从不带花括号的 src/web-api.js 文件导入,您应该在 src/webfile-api.js 中有一个export default something

没有花括号

class WebApi {...};
export default WebApi;

在你的文件中

import WebApi from './src/web-api.js'

// 这里,src/web-api.js 文件中带有export default 的元素应在任何地方不带花括号的情况下导入。 PS:每个文件必须只有一个export default

带花括号

export { WebApi }

在您的文件中 import {WebApi} from './src/web-api.js'

Dan Abramov 在这个答案中清楚地解释了 ES6 中的 export/import 方法。 When should I use curly braces for ES6 import?

【讨论】:

    猜你喜欢
    • 2011-04-08
    • 2013-03-11
    • 1970-01-01
    • 2015-06-14
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多