ES6导出默认,具有多个相互引用的功能


76

在es6中,您可以定义这样的功能模块

export default {
    foo() { console.log('foo') }, 
    bar() { console.log('bar') },
    baz() { foo(); bar() }
}

上面的代码似乎是有效的代码,但是如果我调用baz()它,则会引发错误:

ReferenceError: foo is not defined

您如何foo从另一个函数调用?在这种情况下baz

编辑

这是实际上不起作用的代码。我简化了代码,因此只是所需的核心

const tokenManager =  {
  revokeToken(headers) { 
    ... 
  },
  expireToken(headers) {
    ...
  },
  verifyToken(req, res, next) {
    jwt.verify(... => {
      if (err) {
        expireToken(req.headers)
      }
    })
  }
}

export default tokenManager 

错误是

expireToken(req.headers);
        ^
ReferenceError: expireToken is not defined

编辑2

我只是尝试添加tokenManager之前expireToken,它终于可以了


1
查看我或@pawel的答案。要修复,请expireToken(req.headers)tokenManager.expireToken(req.headers)或替换this.expireToken(req.headers)
skozin 2015年

Answers:


151

export default {...}建筑是只是像这样的快捷方式:

const funcs = {
    foo() { console.log('foo') }, 
    bar() { console.log('bar') },
    baz() { foo(); bar() }
}

export default funcs

现在,它必须变得明显,有没有foobar或者baz在模块的范围功能。但是有一个名为funcs(虽然实际上没有名称)的对象,该对象包含这些函数作为其属性,并且将成为模块的默认导出。

因此,要修复您的代码,请在不使用快捷方式的情况下重新编写代码,并引用foobar作为属性funcs

const funcs = {
    foo() { console.log('foo') }, 
    bar() { console.log('bar') },
    baz() { funcs.foo(); funcs.bar() } // here is the fix
}

export default funcs

另一种选择是使用this关键字来引用funcs对象,而不必像@pawel所指出的那样明确声明它。

另一个选择(也是我通常更喜欢的一个选择)是在模块范围内声明这些函数。这允许直接引用它们:

function foo() { console.log('foo') }
function bar() { console.log('bar') }
function baz() { foo(); bar() }

export default {foo, bar, baz}

而且,如果您希望方便地使用默认导出功能可以单独导入项目,则还可以单独导出所有功能:

// util.js

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

export default {foo, bar, baz}

// a.js, using default export

import util from './util'
util.foo()

// b.js, using named exports

import {bar} from './util'
bar()

或者,正如@loganfsmyth建议的那样,您可以不使用默认导出而只使用import * as util from './util'一个对象中的所有命名导出。


我试过了,但是没用。我已经用实际代码编辑了问题。您能看到这里出了什么问题吗?
chrs

1
@chrs,在您的问题下查看我的评论。您需要替换expireTokentokenManager.expireToken
skozin

@chrs我快了一分钟;)但是我不介意,我喜欢这里的最后一个建议(export default { foo, bar, baz }),并且可能自己使用它。
Pawel 2015年

如果您希望方便地使用默认导出功能,并且希望能够分别导入项目”,那么您不应将对象文字重新导出为默认值,而只需编写即可import * as util from './util'。这正是导入名称空间的目的。
Bergi

26

一种选择是更换模块。通常,如果要导出带有一堆函数的对象,则导出一堆命名函数会更容易,例如

export function foo() { console.log('foo') }, 
export function bar() { console.log('bar') },
export function baz() { foo(); bar() }

在这种情况下,您将导出所有带有名称的函数,因此您可以执行

import * as fns from './foo';

获取具有每个函数的属性的对象,而不是用于第一个示例的导入:

import fns from './foo';

3
这绝对是上乘的解决方案。使用命名的导出而不是默认对象。
Bergi 2015年

12

tl; dr: baz() { this.foo(); this.bar() }

在ES2015中,此构造:

var obj = {
    foo() { console.log('foo') }
}

等于此ES5代码:

var obj = {
    foo : function foo() { console.log('foo') }
}

exports.default = {} 就像创建对象一样,您的默认导出将转换为ES5代码,如下所示:

exports['default'] = {
    foo: function foo() {
        console.log('foo');
    },
    bar: function bar() {
        console.log('bar');
    },
    baz: function baz() {
        foo();bar();
    }
};

现在,它很明显(我希望)baz试图调用foobar在外部范围的某个地方定义(未定义)。但是this.fooandthis.bar将解析为exports['default']object中定义的键。因此,默认的导出引用了自己的方法,如下所示:

export default {
    foo() { console.log('foo') }, 
    bar() { console.log('bar') },
    baz() { this.foo(); this.bar() }
}

请参阅babel repl编译的代码


当我像您在上一个示例中那样执行操作时,我仍然会得到TypeError: Cannot read property 'foo' of undefined-我想念的是什么?
leonheess

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.