วิธีการส่งออกคลาส ES6 ในโหนด 4 อย่างถูกต้อง?


116

ฉันกำหนดคลาสในโมดูล:

"use strict";

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

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

module.export.AspectType = AspectType;

แต่ฉันได้รับข้อความแสดงข้อผิดพลาดต่อไปนี้:

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

ฉันจะส่งออกคลาสนี้และใช้ในโมดูลอื่นได้อย่างไร ฉันเคยเห็นคำถาม SO อื่น ๆ แต่ฉันได้รับข้อความแสดงข้อผิดพลาดอื่น ๆ เมื่อฉันพยายามใช้วิธีแก้ไข


2
ใน ES6 คุณไม่จำเป็นต้องใช้'use strict'ในโมดูลหรือคลาส พฤติกรรมเริ่มต้น อ้าง 10.2.1 Strict Mode Code
Jason Leach

คำตอบ:


118

หากคุณใช้ ES6 ในโหนด 4 คุณจะไม่สามารถใช้ไวยากรณ์ของโมดูล ES6 โดยไม่มีทรานสไพเลอร์ แต่โมดูล CommonJS (โมดูลมาตรฐานของโหนด) จะทำงานเหมือนกัน

module.export.AspectType

ควรจะเป็น

module.exports.AspectType

จึงเกิดข้อผิดพลาด "ไม่สามารถตั้งค่าคุณสมบัติ 'AspectType ของไม่ได้กำหนด" module.export === undefinedเพราะ

นอกจากนี้สำหรับ

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

คุณสามารถเขียน

class AspectType {
    // ...    
}

และได้รับพฤติกรรมเดียวกันเป็นหลัก


27
OMG exportแทนexportsฉันพลาดได้อย่างไร?
Jérôme Verstrynge

1
ในตอนท้ายฉันใส่module.exports = ClassNameและมันก็ใช้ได้ดี
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 คุณควรเพิ่มคำอธิบายว่าวิธีนี้แก้ไขคำถามได้อย่างไร
Alexis Tyler

สิ่งนี้ทำให้เกิดข้อผิดพลาด: Uncaught TypeError: ไม่สามารถกำหนดให้อ่านอย่างเดียวคุณสมบัติ 'ส่งออก' ของวัตถุ '# <วัตถุ>' ทำไมถึงได้รับการโหวตมากขนาดนี้?
henon

ฉันคิดว่าการใส่คำจำกัดความของคลาสทั้งหมดไว้ในการกำหนดการส่งออกเป็นรูปแบบการต่อต้านเมื่อบรรทัดเดียวในตอนท้ายควรทำสิ่งเดียวกัน
user1944491

44

ด้วย ECMAScript 2015 คุณสามารถส่งออกและนำเข้าคลาสต่างๆเช่นนี้ได้

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

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

module.exports = {
    Person,
    Animal
};

จากนั้นคุณใช้ที่ไหน:

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

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

ในกรณีที่ชื่อชนกันหรือคุณต้องการชื่ออื่นคุณสามารถเปลี่ยนชื่อได้ดังนี้:

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

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

1
ไม่ถูกต้อง. เหตุผล: หากคุณใช้ ES6 ในโหนด 4 คุณจะไม่สามารถใช้ไวยากรณ์ของโมดูล ES6 โดยไม่มีทรานสไพเลอร์ แต่โมดูล CommonJS (โมดูลมาตรฐานของโหนด) จะทำงานเหมือนกัน (ตามด้านบน)
AaronHS

นอกจากนี้คุณไม่ควรประกาศสองคลาสในไฟล์เดียวกัน
ariel

เป็นเรื่องปกติที่จะมีคลาส "ส่วนตัวเหมือน" (ที่ช่วยคลาสสาธารณะเดี่ยว) ให้อยู่ในไฟล์เดียวกันตราบเท่าที่ไม่ได้ส่งออกคลาสส่วนตัว นอกจากนี้ยังยอมรับได้หากคุณยังไม่ได้ปรับโครงสร้างใหม่เป็นสองไฟล์ เมื่อทำเช่นนั้นอย่าลืมแยกการทดสอบของคุณเพื่อแยกไฟล์ด้วย หรือเพียงแค่ทำในสิ่งที่คุณต้องการสำหรับสถานการณ์ของคุณ
TamusJRoyce

@AaronHS ความแตกต่างที่แน่นอนกับที่คุณอ้างถึงคืออะไร? ยังไม่ชัดเจนในคำตอบ "ด้านบน" เช่นกัน
user1944491

16

ใช้

// aspect-type.js
class AspectType {

}

export default AspectType;

แล้วจึงจะนำเข้าได้

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

อ่านhttp://babeljs.io/docs/learn-es2015/#modulesสำหรับรายละเอียดเพิ่มเติม


1
ฉันได้รับSyntaxError: Unexpected reserved wordคุณสามารถให้ตัวอย่างโค้ดแบบเต็มได้หรือไม่?
Jérôme Verstrynge

9
ไม่มีการใช้การส่งออกและนำเข้าใน V8 ที่โหนดใช้ คุณยังคงต้องใช้module.exports
Evan Lucas

2
... หรือ Transpile (เช่น Babel) แท้จริง NodeJS มีคุณสมบัติ ES6 ส่วนใหญ่ .. ไม่รวม import / export(ยังคงเป็นจริงพฤษภาคม 2017)
Frank Nocke

12

นิพจน์คลาสสามารถใช้เพื่อความเรียบง่าย

 // 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
เพียงคำเตือนในโหนดนี้ขึ้นอยู่กับลำดับการโหลดโมดูล ดังนั้นควรระมัดระวังในการใช้สิ่งนี้ หากคุณเปลี่ยนชื่อไฟล์เหล่านี้ตามตัวอย่างจะไม่ทำงาน
Dustin

12

ฉันเขียนแบบนี้

ในไฟล์ AspectType:

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

และนำเข้าดังนี้:

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

10

คำตอบอื่น ๆ หลายคำตอบใกล้เคียงกัน แต่จริงๆแล้วฉันคิดว่าคุณควรใช้ไวยากรณ์ที่เรียบง่ายและสะอาดที่สุด OP ร้องขอวิธีการส่งออกคลาสใน ES6 / ES2015 ฉันไม่คิดว่าคุณจะสะอาดได้มากกว่านี้:

'use strict';

export default class ClassName {
  constructor () {
  }
}

2
ไม่ถูกต้อง. เหตุผล: หากคุณใช้ ES6 ในโหนด 4 คุณจะไม่สามารถใช้ไวยากรณ์ของโมดูล ES6 โดยไม่มีทรานสไพเลอร์ แต่โมดูล CommonJS (โมดูลมาตรฐานของโหนด) จะทำงานเหมือนกัน (ตามด้านบน)
AaronHS

3
ใครที่ยังใช้ Node 4 อยู่ ฉันคิดว่านี่เป็นคำตอบที่ถูกต้องสำหรับคน 99%
ลัง

มันอยู่ในชื่อคำถาม
AaronHS

0

ผมมีปัญหาเหมือนกัน. สิ่งที่ฉันพบคือฉันเรียกวัตถุการรับของฉันด้วยชื่อเดียวกับชื่อคลาส ตัวอย่าง:

const AspectType = new AspectType();

สิ่งนี้ทำให้สับสนไปทางนั้น ... หวังว่านี่จะช่วยได้


0

บางครั้งฉันต้องประกาศหลายคลาสในไฟล์เดียวหรือฉันต้องการส่งออกคลาสพื้นฐานและเก็บชื่อไว้ที่ส่งออกเนื่องจากโปรแกรมแก้ไข JetBrains ของฉันเข้าใจดีกว่า ฉันเพิ่งใช้

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

และที่อื่น:

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

1
นี่เป็นวิธีที่ไม่ดีในการทำเช่นนี้ ... มันจะส่งผลให้เกิดการปะทะกันในบางวัน
Brad

ใช่ดี ไม่มีปัญหาเรื่องการชนกันในโครงการของเจ้าของ และถ้าคุณนำเข้าคลาสผ่าน require / module.exports อย่างหมดจดคุณก็แค่เปลี่ยนปัญหาเป็นชื่อโมดูล
Jelmer Jellema

หยุดพยายามเขียน PHP ใน JavaScript: P Jokes กัน - อย่างที่คนอื่นพูดนี่เป็นเพียงการตั้งค่าตัวเองสำหรับปัญหาในภายหลัง Globals เป็นความคิดที่แย่มากไม่ดีเลยแย่มาก
robertmain

1
มีไว้สำหรับผู้ที่ไม่สามารถติดตามรหัสของตนเองได้ อย่าลืมว่าชื่อไฟล์ที่ใช้ในต้องเป็นชื่อโลกด้วย ความเชื่อที่ไม่มีโลกก็มีข้อ จำกัด เช่นกัน
Jelmer Jellema

ดี @ TimHobbs สิ่งที่เด็ก ๆ พูด .. สิ่งต่างๆเช่น "พวกเขาเป็นเพียงช่วงเวลา" นั่นเป็นข้อโต้แย้งที่คุณได้ยินจากผู้คนโดยไม่มีข้อโต้แย้งที่แท้จริง คุณรู้. แม้แต่ NodeJs ก็ใช้ globals ไม่มีปัญหาแม้แต่น้อยเมื่อคุณมีกรอบการทำงานที่กำหนดไว้อย่างดีและมีเอกสารทั่วโลกอย่างดี ยินดีที่ได้ทราบว่าหลังจากเรียนมาหลายปีจบการศึกษาเกียรตินิยมและเลี้ยงตัวเองและครอบครัวมา 20 ปีแล้วมันเป็นแค่ "สิ่งที่ฉันอยากทำต่อไป" โต้แย้งหรือหยุดทำตัวเหมือนเด็ก
Jelmer Jellema
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.