Jak poprawnie wyeksportować klasę ES6 w Node 4?


115

Zdefiniowałem klasę w module:

"use strict";

var AspectTypeModule = function() {};
module.exports = AspectTypeModule;

var AspectType = class AspectType {
    // ...    
};

module.export.AspectType = AspectType;

Ale pojawia się następujący komunikat o błędzie:

TypeError: Cannot set property 'AspectType' of undefined
    at Object.<anonymous> (...\AspectType.js:30:26)
    at Module._compile (module.js:434:26)
    ....

Jak mam wyeksportować tę klasę i użyć jej w innym module? Widziałem inne pytania SO, ale otrzymuję inne komunikaty o błędach, gdy próbuję wdrożyć ich rozwiązania.


2
W ES6 nie potrzebujesz 'use strict'modułu ani klasy; jest to zachowanie domyślne. Nr ref. 10.2.1 Kod trybu ścisłego
Jason Leach

Odpowiedzi:


117

Jeśli używasz ES6 w węźle 4, nie możesz używać składni modułu ES6 bez transpilera, ale moduły CommonJS (standardowe moduły węzła) działają tak samo.

module.export.AspectType

Powinien być

module.exports.AspectType

stąd komunikat o błędzie „Nie można ustawić właściwości„ AspectType ”na wartość undefined”, ponieważ module.export === undefined.

Także dla

var AspectType = class AspectType {
    // ...    
};

możesz po prostu napisać

class AspectType {
    // ...    
}

i uzyskaj zasadniczo takie samo zachowanie.


27
OMG exportzamiast exports, jak mogłem to przegapić?
Jérôme Verstrynge

1
na koniec umieściłem module.exports = ClassNamei działa dobrze
David Welborn

113
// person.js
'use strict';

module.exports = class Person {
   constructor(firstName, lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
   }

   display() {
       console.log(this.firstName + " " + this.lastName);
   }
}

 

// index.js
'use strict';

var Person = require('./person.js');

var someone = new Person("First name", "Last name");
someone.display();

2
@sitrakay naprawdę powinieneś dodać wyjaśnienie, jak to rozwiązuje problem.
Alexis Tyler

w ten sposób pojawia się błąd: Uncaught TypeError: Nie można przypisać do właściwości tylko do odczytu „eksportu” obiektu „# <Object>”, dlaczego jest to tak bardzo przychylne?
henon

Myślę, że umieszczenie całej definicji klasy wewnątrz przypisania eksportu jest wzorcem anty, gdy pojedyncza linia na końcu powinna robić to samo.
user1944491

44

Dzięki ECMAScript 2015 możesz eksportować i importować wiele takich klas

class Person
{
    constructor()
    {
        this.type = "Person";
    }
}

class Animal{
    constructor()
    {
        this.type = "Animal";
    }
}

module.exports = {
    Person,
    Animal
};

wtedy gdzie ich używasz:

const { Animal, Person } = require("classes");

const animal = new Animal();
const person = new Person();

W przypadku kolizji nazw lub jeśli wolisz inne nazwy, możesz je zmienić w następujący sposób:

const { Animal : OtherAnimal, Person : OtherPerson} = require("./classes");

const animal = new OtherAnimal();
const person = new OtherPerson();

1
Źle. Przyczyna: jeśli używasz ES6 w węźle 4, nie możesz używać składni modułu ES6 bez transpilera, ale moduły CommonJS (standardowe moduły węzła) działają tak samo. (jak powyżej)
AaronHS

Nie powinieneś także deklarować dwóch klas w tym samym pliku
ariel

Dobrze jest mieć klasy „podobne do prywatnych” (które pomagają pojedynczej klasie publicznej) w tym samym pliku, o ile klasy prywatne nie są eksportowane. Jest to również dopuszczalne, jeśli jeszcze nie dokonałeś ich refaktoryzacji na dwa pliki. Robiąc to, nie zapomnij podzielić testów na oddzielne pliki. Lub po prostu zrób to, czego potrzebujesz w swojej sytuacji.
TamusJRoyce

@AaronHS Jaka jest dokładna różnica, do której się odnosisz? Nie jest to również jasne w „powyższej” odpowiedzi.
user1944491

16

Posługiwać się

// aspect-type.js
class AspectType {

}

export default AspectType;

Następnie, aby go zaimportować

// some-other-file.js
import AspectType from './aspect-type';

Przeczytaj http://babeljs.io/docs/learn-es2015/#modules, aby uzyskać więcej informacji


1
Otrzymam SyntaxError: Unexpected reserved word, czy możesz podać przykład pełnego kodu?
Jérôme Verstrynge

9
eksport i import nie zostały zaimplementowane w wersji 8, z której korzysta węzeł. Nadal musiałbyś użyćmodule.exports
Evan Lucas

2
... lub transpile (tj. babel), rzeczywiście. NodeJS ma większość funkcji ES6 ... z wyłączeniem import / export(nadal obowiązuje, maj 2017).
Frank Nocke

12

dla uproszczenia można użyć wyrażenia class .

 // Foo.js
'use strict';

// export default class Foo {}
module.exports = class Foo {}

-

// main.js
'use strict';

const Foo = require('./Foo.js');

let Bar = new class extends Foo {
  constructor() {
    super();
    this.name = 'bar';
  }
}

console.log(Bar.name);

4
Tylko ostrzeżenie, w Node jest to uzależnione od kolejności ładowania modułu. Więc uważaj, używając tego. Jeśli zmienisz nazwy tych plików wokół przykładu, nie zadziała.
Dustin

12

Po prostu piszę to w ten sposób

w pliku AspectType:

class AspectType {
  //blah blah
}
module.exports = AspectType;

i zaimportuj w ten sposób:

const AspectType = require('./AspectType');
var aspectType = new AspectType;

10

Kilka innych odpowiedzi jest bliskich, ale szczerze mówiąc, myślę, że lepiej będzie wybrać najczystszą, najprostszą składnię. OP zażądał środków do eksportu klasy w ES6 / ES2015. Nie sądzę, aby można było uzyskać znacznie czystsze niż to:

'use strict';

export default class ClassName {
  constructor () {
  }
}

2
Źle. Powód: jeśli używasz ES6 w węźle 4, nie możesz używać składni modułu ES6 bez transpilera, ale moduły CommonJS (standardowe moduły węzła) działają tak samo. (jak powyżej)
AaronHS

3
Kto do cholery nadal używa Node 4? Myślę, że to poprawna odpowiedź dla 99% ludzi.
Skrzynie

Jest dosłownie w tytule pytania.
AaronHS

0

Miałem ten sam problem. Odkryłem, że nazwałem obiekt odbierający taką samą nazwą jak nazwa klasy. przykład:

const AspectType = new AspectType();

to schrzaniło sprawę w ten sposób ... mam nadzieję, że to pomoże


0

Czasami muszę zadeklarować wiele klas w jednym pliku lub chcę wyeksportować klasy podstawowe i zachować ich nazwy wyeksportowane, ponieważ mój edytor JetBrains lepiej to rozumie. Po prostu używam

global.MyClass = class MyClass { ... };

I gdzie indziej:

require('baseclasses.js');
class MySubclass extends MyClass() { ... }

1
To zły sposób to zrobić ... to będzie prowadzić do kolizji niektóre dni.
Brad

No cóż. Nie ma problemu z kolizjami we własnych projektach. A jeśli importujesz klasy wyłącznie przez require / module.exports, po prostu przenosisz problem na nazwy modułów.
Jelmer Jellema

Przestań pisać PHP w JavaScript: P Żarty na bok - jak wszyscy mówili, jest to po prostu narażanie się na późniejsze problemy. Globale to bardzo zły, niezbyt dobry, bardzo zły pomysł.
robertmain

1
Są przeznaczone dla osób, które nie mogą śledzić własnego kodu. Nie zapominaj, że nazwy plików używane w require są również globalnymi. Dogmat no-globals ma też swoje granice.
Jelmer Jellema

Cóż, @TimHobbs, rzeczy, które mówią dzieciaki… Takie rzeczy jak „Po prostu są, kropka”. Dokładnie takie argumenty można usłyszeć od ludzi, którym brakuje prawdziwych argumentów. Wiesz. Nawet NodeJs używa globali. Nie ma nawet problemu, gdy masz dobrze zdefiniowaną strukturę z dobrze udokumentowanymi danymi globalnymi. Miło słyszeć, że po tylu latach nauki, ukończeniu z wyróżnieniem i karmieniu siebie i mojej rodziny od 20 lat, to po prostu „to, co i tak chcę robić”. Daj mi argument albo przestań zachowywać się jak dzieciak.
Jelmer Jellema
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.