【问题标题】:ES6 export default with multiple functions referring to each otherES6导出默认,多个函数相互引用
【发布时间】:2016-01-15 16:48:27
【问题描述】:

在 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

我刚刚尝试在expireToken 之前添加tokenManager,它终于可以工作了

【问题讨论】:

  • 查看我或@pawel 的回答。要修复,请将 expireToken(req.headers) 替换为 tokenManager.expireToken(req.headers)this.expireToken(req.headers)

标签: javascript ecmascript-6


【解决方案1】:

export default {...} 结构只是这样的捷径:

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

export default funcs

现在必须很明显,模块范围内没有foobarbaz 函数。但是有一个名为 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 对象,而不必显式声明它,as @pawel has pointed out

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

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,请在您的问题下查看我的评论。您需要将expireToken 替换为tokenManager.expireToken
  • @chrs 我快了一分钟 ;) 但我不介意,我喜欢这里的最后一个建议 (export default { foo, bar, baz }),并且可能会自己使用它。
  • "如果您想要方便的默认导出和单独导入项目的能力" - 那么您不应该将对象文字重新导出为默认值,而只需编写 @987654340 @。这正是命名空间导入的目的。
【解决方案2】:

另一种方法是更改​​您的模块。通常,如果您要导出带有一堆函数的对象,则导出一堆命名函数会更容易,例如

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】:

tl;博士: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.foothis.bar 将解析为exports['default'] 对象中定义的键。所以引用它自己的方法的默认导出看起来像这样:

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

babel repl transpiled code

【讨论】:

  • 当我像你上一个例子那样做时,我仍然得到TypeError: Cannot read property 'foo' of undefined - 我错过了什么?
猜你喜欢
  • 2016-06-03
  • 2017-12-02
  • 1970-01-01
  • 2014-09-15
  • 1970-01-01
  • 2018-10-19
  • 2020-06-30
  • 2016-08-02
  • 2017-06-09
相关资源
最近更新 更多