节点ES6:类不是函数

时间:2016-03-28 02:03:10

标签: javascript node.js

我正在尝试找出我在代码中遇到的错误。我写了一个简单的例子,它使用类a,b和条目文件c复制了bug。

我的代码在哪里出错?

修改

许多答案都与我的代码结构有关!我想澄清所需的功能。

  1. a:需要b的静态实例。因此,A需要B。

  2. b函数(无静态):仅接受instanceof a的对象。因此,B需要A。

  3. 具体来说,我有一个"短语" (a)类和" Parser" (b)类。解析器只接受短语。短语使用其静态解析器实例在创建时解析自己。

    a.js

    'use strict';
    
    let b = require('./b.js');
    
    class a {
        constructor() {
    
        }
    }
    
    new b();
    
    module.exports = a;
    

    b.js

    'use strict';
    
    let a = require('./a.js');
    
    class b {
        constructor() {
    
        }
    }
    
    module.exports = b;
    

    c.js

    'use strict';
    
    let b = require('./b.js');
    new b();
    

    运行: node c.js

    错误:

    C:\code\a.js:11
    new b();
    ^
    
    TypeError: b is not a function
        at Object.<anonymous> (C:\code\projects\elegance\data-frog\tag\datastructures\a.js:11:7)
        at Module._compile (module.js:413:34)
        at Object.Module._extensions..js (module.js:422:10)
        at Module.load (module.js:357:32)
        at Function.Module._load (module.js:314:12)
        at Module.require (module.js:367:17)
        at require (internal/module.js:16:19)
        at Object.<anonymous> (C:\code\projects\elegance\data-frog\tag\datastructures\b.js:3:9)
        at Module._compile (module.js:413:34)
        at Object.Module._extensions..js (module.js:422:10)
    

3 个答案:

答案 0 :(得分:2)

您是从另一个内部递归调用每个模块,因此当您在a模块中导入b时,它还没有准备好。

你不应该在b模块中要求a.js.

如果出于某种原因需要这样做,请重构代码,因为这是一个反模式。

您可以使用第三个需要a和b的模块:

const A = require('a'); //Export the class, not the instance
const B = require('b'); //Export the class, not the instance

var a = new A();
var b = new B();

a.b = b;

这样您就可以确定a和b是各自类的实例,或者如果您愿意,仍然可以使用instanceof所需的类。

另外,如果我可以建议,请为您的类使用大写命名。

答案 1 :(得分:2)

更新

根据您的编辑,我的直接建议是,如果您选择保留它,则继续使用class Phrase,特别是因为您希望能够记录对象的类型...
...但是要将该构造函数用作其他语言中的struct

你的Parser可以知道Phrase,因为它解析了它们,但是解析器接受鸭子类型的条目真的有害,因为灵活性的差异很大,如果你检查您的方法想要的接口(实际使用的结构上的字段),而不是检查严格的实例。

一个简单的示例可能是从Web服务加载短语列表。在解析它们之前,你真的需要将每一行实例化为一个短语吗?

这是一个如何处理你有一个低级结构的情况的例子,它不需要DI的工厂(因为它是如此低级别),而是可以直接导入到Parser模块。

// phrase.js
class Phrase {
  constructor (content = "") {
    this.content = content;
  }

  static from (phrase) {
    return new Phrase(phrase.content);
  }

  static isPhrase (phrase) {
    return phrase && phrase.content !== null && phrase.content !== undefined;
  }
}

export default Phrase; // or module.exports


// parser.js
import Parser from "./parser"; // or require, whatever floats your boat
class Parser {
  static parse ( input = "" ) {
    const preparedContent = Phrase.isPhrase( input )
      ? Parser.prepareContent( input.content )
      : Parser.prepareContent( input );

    return new Phrase(content);
  }

  static prepareContent ( input = "" ) {
    // ...
  }

  parse (content) {
    return Parser.parse(content);
  }
}

export default Parser;

我现在可以创建Parser的实例,或者只是静态使用它 我可以把它原始输入,或者我可以把它换成短语,它会做正确的事情 而且,我不依赖于Parser能够定义Phrase是什么。 Parser依靠Phrase构建器来了解Phrase是什么。

Parser总是返回一个“解析”短语的新实例,但它的输入现在更加轻松。同样,基于即将发布的内容,您现在可以使用您的输入做更多理智的事情(即:提供良好的默认值,例如安全地返回空短语(我的示例世界中的phrase.content可能是空字符串) ),而不是基于instanceof)返回null或投掷。

查看我在其他地方提供的答案,了解更多详细信息(并查看问题,看看他在目前的地点与目前的地点完全相同的路障)。

ES6 modules and inheritance

但答案是,你不应该依赖循环依赖,这会对你的代码库造成可怕的,可怕的事情。

如果你真的,真的,真的,真的需要这样做(你没有),你应该使用Factory来确保构建/使用正确的实例,并将工厂注入你的应用程序,而不是类本身。

如果您严重 依赖,批发,typeofinstanceof功能,以确保您的应用程序的坚固性 - 特别是以支票需要通知的方式引用,那么您的应用程序首先不是很坚固

你的课程不需要彼此了解,当你把他们的建筑委托给工厂时,如果这是你选择的路径,那么课程也不应该知道工厂。

答案 2 :(得分:1)

可能会使这更复杂。

查看这个简单的灯类。

class Light {
  constructor(state = false) {
    this.state = state;
  }
  on() {
    this.state = true;
    return this.state;
  }
  off() {
    this.state = false;
    return this.state;
  }
}

const myLight = new Light();
myLight.on()

您可以看到状态是在构造函数中定义的。

希望这有帮助。