export/import 语句中有和没有大括号符号有什么区别?

What is the difference between with and without curly bracket notation in export/import statements?

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

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

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';

为什么一个 class 有大括号,另一个没有大括号?一般来说,我怎么知道什么时候使用和不使用大括号?

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

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

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

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

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

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

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

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

时不需要用大括号括起来的原因

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

ES6 提供了多种 方式来通过import/export 管理模块。但基本上有两个主要策略:

  1. 默认 export/import export defaultimport module from './module'
  2. Multiple exports/imports with export and import {member} from './module' or import * as module from './module'

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


模块到 export/import

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

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

策略#1:默认export/import

导出 (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:多个exports/imports

导出 (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.

在你的例子中,如果你从 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 方法。