ES6-Exportstandard mit mehreren Funktionen, die aufeinander verweisen

76

In es6 können Sie ein solches Funktionsmodul definieren

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

Der obige Code scheint ein gültiger Code zu sein, aber wenn ich baz()ihn aufrufe, wird ein Fehler ausgegeben:

ReferenceError: foo is not defined

Wie ruft man foovon einer anderen Funktion aus auf? in diesem Fallbaz

Bearbeiten

Hier ist der Code, der eigentlich nicht funktioniert. Ich habe den Code so vereinfacht, dass er bei Bedarf nur der Kern ist

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

export default tokenManager 

und der Fehler ist

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

Bearbeiten 2

Ich Hinzufügen gerade versucht , tokenManagerbevor expireTokenes schließlich funktioniert

chrs
quelle
1
Siehe meine oder @ pawels Antwort. Um dies zu beheben, ersetzen Sie expireToken(req.headers)mit tokenManager.expireToken(req.headers)oder mit this.expireToken(req.headers).
Skozin

Antworten:

151

Die export default {...}Konstruktion ist nur eine Abkürzung für so etwas:

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

export default funcs

Es muss jetzt offensichtlich geworden , dass es keine foo, baroder bazFunktionen im Rahmen des Moduls. Es gibt jedoch ein Objekt mit dem Namen funcs(obwohl es in Wirklichkeit keinen Namen hat), das diese Funktionen als Eigenschaften enthält und zum Standardexport des Moduls wird.

Um Ihren Code zu reparieren, schreiben Sie ihn neu, ohne die Verknüpfung zu verwenden, und verweisen Sie auf foound barals Eigenschaften von funcs:

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

export default funcs

Eine andere Möglichkeit besteht darin, ein thisSchlüsselwort zu verwenden, um auf ein funcsObjekt zu verweisen, ohne es explizit deklarieren zu müssen, wie @pawel hervorgehoben hat .

Eine weitere Option (und die, die ich im Allgemeinen bevorzuge) besteht darin, diese Funktionen im Modulbereich zu deklarieren. Dies ermöglicht es, direkt auf sie zu verweisen:

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

export default {foo, bar, baz}

Wenn Sie den Standard-Export und die Möglichkeit zum individuellen Importieren von Elementen nutzen möchten , können Sie auch alle Funktionen einzeln exportieren:

// 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()

Oder, wie @loganfsmyth vorgeschlagen hat, können Sie auf den Standardexport verzichten und nur verwenden import * as util from './util', um alle benannten Exporte in einem Objekt abzurufen .

Skozin
quelle
Ich habe es versucht, konnte es aber nicht zum Laufen bringen. Ich habe die Frage mit dem echten Code bearbeitet. Kannst du sehen, was hier schief geht?
chrs
1
@chrs, siehe meinen Kommentar unter Ihrer Frage. Sie ersetzen müssen expireTokenmit tokenManager.expireToken.
Skozin
@chrs Ich war um eine Minute schneller;) Aber es macht mir nichts aus, ich mag den letzten Vorschlag hier ( export default { foo, bar, baz }) und würde ihn wahrscheinlich selbst verwenden.
Pawel
" Wenn Sie den Standard-Export und die Möglichkeit zum individuellen Importieren von Elementen wünschen " - sollten Sie ein Objektliteral nicht standardmäßig erneut exportieren, sondern einfach schreiben import * as util from './util'. Genau dafür wurden Namespace-Importe gemacht.
Bergi
26

Eine Alternative besteht darin, Ihr Modul zu wechseln. Wenn Sie ein Objekt mit einer Reihe von Funktionen exportieren, ist es im Allgemeinen einfacher, eine Reihe benannter Funktionen zu exportieren, z

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

In diesem Fall exportieren Sie alle Funktionen mit Namen, damit Sie dies tun können

import * as fns from './foo';

So erhalten Sie ein Objekt mit Eigenschaften für jede Funktion anstelle des Imports, den Sie für Ihr erstes Beispiel verwenden würden:

import fns from './foo';
loganfsmyth
quelle
3
Dies ist definitiv die überlegene Lösung. Verwenden Sie benannte Exporte anstelle von Standardobjekten.
Bergi
12

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

In ES2015 dieses Konstrukt:

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

entspricht diesem ES5-Code:

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

exports.default = {} Wenn Sie ein Objekt erstellen, wird Ihr Standardexport wie folgt in ES5-Code übersetzt:

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

Jetzt ist es irgendwie offensichtlich (ich hoffe), dass bazversucht wird, irgendwo im äußeren Bereich aufzurufen foound zu bardefinieren, die undefiniert sind. Aber this.foound this.barwird in die im exports['default']Objekt definierten Schlüssel aufgelöst . Der Standardexport, der auf seine eigenen Methoden verweist, sieht also folgendermaßen aus:

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

Siehe babel repl transpiled Code .

pawel
quelle
Wenn ich es wie in Ihrem letzten Beispiel mache, bekomme ich immer noch TypeError: Cannot read property 'foo' of undefined- was fehlt mir?
Leonheess