使用require导入的Node.js ES6类

135

到目前为止,我已经按以下方式在node.js中创建了类和模块:

    var fs = require('fs');

var animalModule = (function () {
    /**
     * Constructor initialize object
     * @constructor
     */
    var Animal = function (name) {
        this.name = name;
    };

    Animal.prototype.print = function () {
        console.log('Name is :'+ this.name);
    };

    return {
        Animal: Animal
    }
}());

module.exports = animalModule;

现在在ES6中,您可以像这样创建“实际的”类:


class Animal{

 constructor(name){
    this.name = name ;
 }

 print(){
    console.log('Name is :'+ this.name);
 }
}

首先,我很喜欢这个 :) 但是它引发了一个问题。你如何将其与node.js的模块结构结合使用?

假设你有一个类,在其中想要使用一个模块进行演示,比如说你想要使用fs,那么你可以创建你的文件:


Animal.js

var fs = require('fs');
class Animal{

 constructor(name){
    this.name = name ;
 }

 print(){
    console.log('Name is :'+ this.name);
 }
}

这样做是否正确?

另外,如何将这个类暴露给我 Node 项目中的其他文件?如果您在另一个文件中使用它,仍然可以扩展这个类吗?

希望有人能够回答这些问题:)


3
只需像在ES5中对待构造函数名称一样对待ES6类名称。它们是相同的。ES6语法只是一种语法糖,会创建完全相同的底层原型、构造函数和对象。 - jfriend00
在具有自己的模块作用域的节点模块中,创建animalModule的IIFE是相当无意义的。 - Bergi
5个回答

205

是的,你的例子可以正常运行。

至于暴露你的类,你可以像导出其他任何内容一样导出一个类:export

class Animal {...}
module.exports = Animal;

或者更短:

module.exports = class Animal {

};

一旦被导入到另一个模块中,你就可以像在该文件中定义的那样对待它:

var Animal = require('./Animal');

class Cat extends Animal {
    ...
}

8
你还可以像这样做:module.exports = class Animal {} - Paul
没错,我总是忘记在赋值时可以给变量命名。 - rossipedia
这归结于代码风格和清晰度。module.exports 通常用于匿名导出,而 export 用于命名导出。这是一种基本的编码礼仪(可以这么说),可以帮助其他人知道如何导入你的类、模块等���。 - greg.arnott
8
“module.exports = Animal;”是最直接的答案或等价于问题的答案,同时在调用代码中,“const Animal = require('./animal');”也是有效的。请问是否需要更新您的回答以包含这些信息? - sun
1
请注意,class Animal {...} module.exports = Animalmodule.exports = class Animal {...}不同:在后一种变体中,您不能在所需的文件中使用new Animal(),因为类名仅从类内部可访问。 - wortwart
看起来我可以像这样分配一个实例(需要在require周围加上括号):const myAnimal = new (require('./Animal'))(); - user1944491

20

只需像 ES5 的方式处理构造函数名一样处理 ES6 类名。它们是一样的。

ES6 语法只是一种语法糖,创建了完全相同的底层原型、构造函数和对象。

那么,在你的 ES6 示例中:

// animal.js
class Animal {
    ...
}

var a = new Animal();

module.exports = {Animal: Animal};

或者出口声明可以简写为:

module.exports = { Animal };

你可以把Animal看作是对象的构造函数(就像在ES5中所做的那样)。你可以导出构造函数。你可以使用new Animal()调用构造函数。使用它的方式完全相同,只是声明语法不同。甚至还有一个Animal.prototype,其中包含了所有的方法。ES6的方式确实会创建相同的编码结果,只是语法更加花哨/优美。


在导入方面,这将像这样使用:
const Animal = require('./animal.js').Animal;

let a = new Animal();

或者,它可以只是:

const { Animal } = require('./animal.js');

let a = new Animal();

这个方案将 Animal 构造函数作为 .Animal 属性导出,允许您从该模块中导出多个内容。
如果您不需要导出多个内容,可以这样做:
// animal.js
class Animal {
    ...
}

module.exports = Animal;

然后使用以下代码进行导入:

const Animal = require('./animal.js');

let a = new Animal();

我不知道为什么,但这对我来说根本不起作用。module.exports = Animal 是唯一可行的解决方案。 - Sam
1
@Sam - 我的导出所显示的需要与你的导出所显示的不同的 require(),这就是为什么一个可以工作而另一个不能的原因。你必须将导入的方式与导出的定义相匹配。更多详细信息已添加到我的答案中以解释这一点。 - jfriend00
@jfriend00 - 你会怎样声明私有方法和数据? - milesmeow
@milesmeow - 请参阅https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/Private_class_fields。 - jfriend00

8
ES6的require方式是使用import。您可以通过export导出您的类,并使用import { ClassName } from 'path/to/ClassName'语法在其他地方导入它。
import fs from 'fs';
export default class Animal {

  constructor(name){
    this.name = name ;
  }

  print(){
    console.log('Name is :'+ this.name);
  }
}

import Animal from 'path/to/Animal.js';

4
澄清一下这只是一个选项,而不是必须的。这是ES6模块语法,但你仍然可以使用ES6类与Node的普通CommonJS导出。没有要求你在类中使用ES6导出语法。称其为“ES6方式”有点误导。 - loganfsmyth
2
没错,这是个人偏好。就我个人而言,为了语法的一致性,我会使用 import 而不是 require - Fan Jin
2
是的,这是一个可靠的方法,我也这样做,只要记住 Babel 的 import 与 CommonJS 模块互操作的方式不太可能在 Node 中起作用,因此未来可能需要进行代码更改才能与 Node 兼容而不使用 Babel。 - loganfsmyth
4
在Node 10中,ES6模块(import和export)仍处于实验阶段,需要在启动Node时打开。 - dcorking
补充@dorking的观点。 Node 10.15.3是LTS(长期支持)版本,将一直持续到2020年4月。 这里有更多详细信息:https://nodejs.org/en/about/releases/ - gtzilla
@gtzilla,这已经不再是真实情况了,现在是2019年,LTS版本已经更新到12.13.1。 - tam.teixeira

4

在Node中使用类 -

这里我们正在引入ReadWrite模块并调用makeObject(),它返回ReadWrite类的对象。我们使用它来调用方法。 index.js

const ReadWrite = require('./ReadWrite').makeObject();
const express = require('express');
const app = express();

class Start {
  constructor() {
    const server = app.listen(8081),
     host = server.address().address,
     port = server.address().port
    console.log("Example app listening at http://%s:%s", host, port);
    console.log('Running');

  }

  async route(req, res, next) {
    const result = await ReadWrite.readWrite();
    res.send(result);
  }
}

const obj1 = new Start();
app.get('/', obj1.route);
module.exports = Start;

ReadWrite.js

在这里,我们创建了一个makeObject方法,它确保只有在对象不可用的情况下才返回一个对象。

class ReadWrite {
    constructor() {
        console.log('Read Write'); 
        this.x;   
    }
    static makeObject() {        
        if (!this.x) {
            this.x = new ReadWrite();
        }
        return this.x;
    }
    read(){
    return "read"
    }

    write(){
        return "write"
    }


    async readWrite() {
        try {
            const obj = ReadWrite.makeObject();
            const result = await Promise.all([ obj.read(), obj.write()])
            console.log(result);
            check();
            return result
        }
        catch(err) {
            console.log(err);

        }
    }
}
module.exports = ReadWrite;

更多说明请转至https://medium.com/@nynptel/node-js-boiler-plate-code-using-singleton-classes-5b479e513f74


1

在类文件中,您可以使用以下方法:

module.exports = class ClassNameHere {
 print() {
  console.log('In print function');
 }
}

或者您可以使用这个语法。
class ClassNameHere{
 print(){
  console.log('In print function');
 }
}

module.exports = ClassNameHere;

另一方面,要在其他文件中使用此类,您需要执行以下步骤。 首先使用以下语法要求该文件: const 任何变量名称 = require('文件路径'); 然后创建一个对象 const 类对象 = new 任何变量名称(); 完成后,您可以使用类对象来访问实际的类变量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接