带有 require 的 Node.js ES6 类

Posted

技术标签:

【中文标题】带有 require 的 Node.js ES6 类【英文标题】:Node.js ES6 classes with require 【发布时间】:2017-07-29 18:41:51 【问题描述】:

所以到目前为止,我已经通过以下方式在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);
 

这是正确的方法吗?

另外,您如何将此类公开给我的节点项目中的其他文件?如果你在一个单独的文件中使用它,你还能扩展这个类吗?

我希望你们中的一些人能够回答这些问题:)

【问题讨论】:

只需将 ES6 类名视为与您在 ES5 方式中处理构造函数名称相同。他们是一样的。 ES6 语法只是语法糖,创建完全相同的底层原型、构造函数和对象。 创建animalModule 的 IIFE 在具有自己模块范围的节点模块中毫无意义。 【参考方案1】:

是的,你的例子可以正常工作。

至于公开你的类,你可以export一个类,就像其他任何东西一样:

class Animal ...
module.exports = Animal;

或更短的:

module.exports = class Animal 

;

一旦导入到另一个模块中,您就可以将其视为已在该文件中定义:

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

class Cat extends Animal 
    ...

【讨论】:

你也可以做类似 module.exports = class Animal 是的,我一直忘记你可以在作业期间命名。 归结为代码风格和清晰度。 module.exports 通常用于匿名导出,而export 用于命名导出。这是一种基本的编码礼节(您可能会说),它可以帮助其他人了解如何导入您的类、模块等。 module.exports = Animal; 将是问题的答案或最直接等价的问题,并且在调用代码中与const Animal = require('./animal'); 一起有效。您可以更新您的答案以包含它吗? 请注意class Animal ... module.exports = Animalmodule.exports = class Animal ... 不同:在后一种变体中,您不能在所需文件中使用new Animal(),因为类名只能从类内部访问。跨度> 【参考方案2】:

只需像对待 ES5 方式中的构造函数名称一样对待 ES6 类名。他们是一样的。

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

因此,在您的 ES6 示例中:

// animal.js
class Animal 
    ...


var a = new Animal();

module.exports = Animal: Animal;

您可以将Animal 视为对象的构造函数(就像您在 ES5 中所做的一样)。您可以导出构造函数。您可以使用new Animal() 调用构造函数。使用它的一切都是一样的。只有声明语法不同。甚至还有一个 Animal.prototype 上面有你所有的方法。 ES6 方式确实创建了相同的编码结果,只是语法更高级/更好。


在导入方面,它会像这样使用:

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

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 - 我的导出显示需要与您的导出显示不同的require(),这就是为什么一个可以工作而另一个不能工作的原因。您必须将导入的工作方式与导出的定义方式相匹配。我的答案中添加了更多详细信息来解释这一点。 @jfriend00 - 你将如何声明私有方法和数据? @milesmeow - 见developer.mozilla.org/en-US/docs/Web/javascript/Reference/…。【参考方案3】:

ES6 的 require 方式是import。你可以export你的类并使用import ClassName from 'path/to/ClassName'syntax将它导入到其他地方。

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';

【讨论】:

最好澄清这是一个选项,但不是必需的。这是 ES6 模块语法,但您仍然可以将 ES6 类与 Node 的普通 CommonJS 导出一起使用。没有要求对类使用 ES6 导出语法。称它为The ES6 way 有点误导。 没错,这是个人喜好。就个人而言,我会使用 import 而不是 require 只是为了语法一致性。 是的,这是一种可靠的方法,我也这样做,请记住,Babel 的 import 与 CommonJS 模块互操作的方式不太可能最终在 Node 中工作,因此它可能需要代码未来的变化是为了兼容 Node without Babel。 ES6 模块(导入和导出)在 Node 10 中仍处于试验阶段,需要在启动节点时开启 补充@dorking 的观点。节点 10.15.3 是 LTS(长期支持)版本,将持续到 2020 年 4 月。此处的其他详细信息:nodejs.org/en/about/releases【参考方案4】:

在节点中使用类 -

这里我们需要 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

【讨论】:

【参考方案5】:

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

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

或者你可以使用这个语法

class ClassNameHere
 print()
  console.log('In print function');
 


module.exports = ClassNameHere;

另一方面,要在任何其他文件中使用此类,您需要执行这些步骤。 首先使用以下语法要求该文件: const anyVariableNameHere = require('filePathHere');

然后创建一个对象 const classObject = new anyVariableNameHere();

在此之后,您可以使用classObject 访问实际的类变量

【讨论】:

以上是关于带有 require 的 Node.js ES6 类的主要内容,如果未能解决你的问题,请参考以下文章

es6和node.js模块的区别

使用Node.js需要与ES6导入/导出

有没有办法取消 node.js 对 require 模块的缓存

有没有办法取消 node.js 对 require 模块的缓存

有没有办法取消 node.js 对 require 模块的缓存

带有 Firebase (FCM) 推送通知的 Node js