Como exportar corretamente uma classe ES6 no Nó 4?

115

Eu defini uma classe em um módulo:

"use strict";

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

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

module.export.AspectType = AspectType;

Mas recebo a seguinte mensagem de erro:

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

Como devo exportar esta classe e usá-la em outro módulo? Já vi outras perguntas do SO, mas recebo outras mensagens de erro quando tento implementar suas soluções.

Jérôme Verstrynge
fonte
2
No ES6 você não precisa 'use strict'de um módulo ou classe; é o comportamento padrão. Ref. 10.2.1 Código de modo estrito
Jason Leach

Respostas:

117

Se você estiver usando ES6 no Nó 4, não poderá usar a sintaxe do módulo ES6 sem um transpiler, mas os módulos CommonJS (módulos padrão do Node) funcionam da mesma forma.

module.export.AspectType

deveria estar

module.exports.AspectType

portanto, a mensagem de erro "Não é possível definir propriedade 'AspectType' de indefinido" porque module.export === undefined.

Também para

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

você pode apenas escrever

class AspectType {
    // ...    
}

e obter essencialmente o mesmo comportamento.

loganfsmyth
fonte
27
OMG em exportvez de exports, como eu perdi isso?
Jérôme Verstrynge
1
no final eu coloquei module.exports = ClassNamee funciona bem
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();
Sitrakay
fonte
2
@sitrakay você realmente deve adicionar uma explicação de como isso corrige a questão.
Alexis Tyler
isso dá o erro: TypeError não capturado: Não é possível atribuir à propriedade somente leitura 'exportações' do objeto '# <Objeto>' por que isso é tão votado a favor?
henon
Acho que colocar uma definição de classe inteira dentro da atribuição de exportações é um antipadrão quando uma única linha no final deve fazer a mesma coisa.
user1944491
44

Com ECMAScript 2015 você pode exportar e importar várias classes como esta

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

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

module.exports = {
    Person,
    Animal
};

então onde você os usa:

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

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

Em caso de conflito de nomes, ou se preferir outros nomes, você pode renomeá-los assim:

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

const animal = new OtherAnimal();
const person = new OtherPerson();
Jonas Brandel
fonte
1
Errado. Motivo: se você estiver usando ES6 no Nó 4, não poderá usar a sintaxe do módulo ES6 sem um transpiler, mas os módulos CommonJS (módulos padrão do Node) funcionam da mesma forma. (conforme acima)
AaronHS
Além disso, você não deve declarar duas classes no mesmo arquivo
ariel
Não há problema em ter classes "semelhantes a privadas" (que auxiliam a única classe pública) no mesmo arquivo, desde que as classes privadas não sejam exportadas. Também é aceitável se você ainda não os refatorou em dois arquivos. Ao fazer isso, não se esqueça de dividir seus testes em arquivos separados também. Ou apenas faça o que você precisa para sua situação.
TamusJRoyce
@AaronHS qual é a diferença exata a que você está se referindo? Também não está claro na resposta "acima".
user1944491
16

Usar

// aspect-type.js
class AspectType {

}

export default AspectType;

Então, para importá-lo

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

Leia http://babeljs.io/docs/learn-es2015/#modules para mais detalhes

Obrigado
fonte
1
Eu recebo um SyntaxError: Unexpected reserved word, você pode fornecer um exemplo de código completo?
Jérôme Verstrynge
9
exportação e importação não foram implementadas no V8 que o nó usa. Você ainda precisaria usarmodule.exports
Evan Lucas
2
... ou transpilar (isto é, babel), de fato. NodeJS tem a maioria dos recursos ES6 .. excluindo import / export(ainda é válido, maio de 2017).
Frank Nocke
12

expressão de classe pode ser usada para simplicidade.

 // 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);
masakielástico
fonte
4
Apenas um aviso, no Node isso está sujeito à ordem de carregamento do módulo. Portanto, tenha cuidado ao usar isso. Se você trocar os nomes desses arquivos pelo exemplo, não funcionará.
Dustin
12

Eu simplesmente escrevo assim

no arquivo AspectType:

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

e importe assim:

const AspectType = require('./AspectType');
var aspectType = new AspectType;
Behnam Ghiaseddin
fonte
10

Várias das outras respostas chegam perto, mas, honestamente, acho melhor você escolher a sintaxe mais limpa e simples. O OP solicitou um meio de exportar uma classe no ES6 / ES2015. Eu não acho que você pode ficar muito mais limpo do que isso:

'use strict';

export default class ClassName {
  constructor () {
  }
}
Caixotes
fonte
2
Errado. Motivo: se você estiver usando ES6 no Nó 4, não poderá usar a sintaxe do módulo ES6 sem um transpiler, mas os módulos CommonJS (módulos padrão do Node) funcionam da mesma forma. (conforme acima)
AaronHS
3
Quem diabos ainda está usando o Nó 4? Acho que essa é uma resposta válida para 99% das pessoas.
Caixas de
Está literalmente no título da pergunta.
AaronHS
0

Eu tive o mesmo problema. O que descobri foi que chamei meu objeto receptor com o mesmo nome da classe. exemplo:

const AspectType = new AspectType();

isso estragou as coisas dessa maneira ... espero que isso ajude

Shahar Taite
fonte
0

Às vezes, preciso declarar várias classes em um arquivo ou desejo exportar classes básicas e manter seus nomes exportados porque meu editor JetBrains entende isso melhor. Eu só uso

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

E em outro lugar:

require('baseclasses.js');
class MySubclass extends MyClass() { ... }
Jelmer Jellema
fonte
1
Esta é uma má maneira de fazer isso ... isso vai resultar em uma colisão algum dia.
Brad
Sim, bem. Nenhum problema com colisões em projetos próprios. E se você simplesmente importar classes por meio de require / module.exports, você está apenas transferindo o problema para os nomes dos módulos.
Jelmer Jellema
Pare de tentar escrever PHP em JavaScript: P Piadas à parte - como todo mundo já disse, isso é apenas uma preparação para problemas mais tarde. Globais são uma ideia muito ruim, muito ruim, muito ruim.
robertmain
1
Eles são para pessoas que não podem rastrear seu próprio código. Não se esqueça de que os nomes de arquivo usados ​​em require também são globais. O dogma não-global também tem seus limites.
Jelmer Jellema
Bem, @TimHobbs, as coisas que as crianças dizem ... Coisas como "Eles simplesmente são, ponto final." Esse é exatamente o tipo de argumento que você ouve de pessoas que não têm argumentos reais. Você sabe. Até mesmo NodeJs usa globais. Não há problema quando você tem uma estrutura bem definida com globais bem documentados. Bom saber que depois de todos esses anos de estudo, graduação cum laude e alimentando a mim e minha família por 20 anos agora, é apenas "o que eu quero fazer de qualquer maneira". Dê-me uma discussão ou pare de agir como uma criança.
Jelmer Jellema