【问题标题】:How to Call Global Variables From Constructors如何从构造函数调用全局变量
【发布时间】:2021-01-10 14:52:39
【问题描述】:

我有一个如下所示的课程:

class MyClass {

    constructor() {
        this.field = 42;
    }
    
    method() {
        return "Hello world!";
    }
}

我想将它的一个实例定义为全局变量,所以我注册了它:

global.MyObject= new MyClass();

这意味着现在可以使用:

console.log(MyObject.field); // 42
console.log(MyObject.method()); // Hello world!

但是,每当我从另一个类调用相同的代码时,它突然变得更加随机:

class OtherClass {

    constructor() {
        console.log(MyObject.field); // undefined
        console.log(MyObject.method()); // TypeError: MyObject.method is not a function
    }
}

有时这有效,有时无效。我不知道它什么时候起作用,什么时候不起作用,只是它不是完全随机的。从同一个地方调用,构造函数要么工作要么不工作。这无助于隔离问题。

似乎当从没有直接require('my-class') 的模块调用类的构造函数时,它不起作用——即使OtherClass 有这种要求?即使每个其他模块都有require?这没有任何意义。

我用两个模块 A 和 B 进行了尝试。如果 A 定义了全局变量,即使没有 require,B 也可以正常访问它们——只要其他人拥有它。

所以...我对它的工作原理感到困惑。可能是一个愚蠢的 JavaScript 噱头,我不是原生 JavaScript 开发人员。

我的设置如下所示:

  • 源/
    • ActualCode(使用将创建 OtherClass 的功能)
  • 测试/
    • 模拟/
      • 我的班级
      • 其他类 (require('MyClass'))
    • ActualCodeTest (require('ActualCode'), require('OtherClass')

OtherClass 中的构造函数在从MyClassOtherClass 调用时将能够访问MyClass,但不能从ActualCodeActualCodeTest 调用。即使按顺序调用(因此全局变量确实存在)。

这意味着更改参数和添加require 是不可能的,因为ActualCode 永远不应该知道测试代码。

问题似乎出在 Mocha 框架上。全局变量不能在“it”内部访问:

console.log(MyObject.field); // 42

it('test', () => {
    console.log(MyObject.field); // undefined
}

如果我删除周围的代码,它将(显然)工作。

如何从类的构造函数中调用全局变量?

【问题讨论】:

  • global 是什么?是这个节点吗?如果是这样,为了使您的代码更便携,您可以考虑改用globalThis。然后你会做globalThis.MyObject.field.. 但我个人无论如何都不会这样做全局变量,而是使用模块。
  • 不要使用全局变量。但是,如果你真的,真的想破坏你的程序安全并让它难以推理,globals 是什么——你在 NodeJS 上吗?如果是这样,请将其标记为这样。如果类构造函数依赖于一条数据,为什么不使用参数呢?
  • @ggorlen 我的代码针对(和内部)一个复杂的 JavaScript 应用程序(不是我的)运行。为了测试这段代码,我正在创建模拟代码。由于“复杂的 JavaScript 应用程序”使用全局变量,我的模拟也需要这样做。因此,使用参数是不可能的,任何不会将该字段放入MyObject.field 的东西也是如此。
  • 提供上下文很好,谢谢,但我怀疑访问是否有效。如果没有minimal reproducible example,除了推测发生了什么之外,很难做更多的事情。

标签: javascript node.js mocha.js


【解决方案1】:

当您将所有内容都放在一个文件中时,此示例代码可以正常工作:

$ cat sample.js 
class MyClass {
    constructor() {
        this.field = 42;
    }

    method() {
        return "Hello world!";
    }
}
global.MyObject = new MyClass();

class OtherClass {
    constructor(props) {
        console.log(MyObject.field);
        console.log(MyObject.method());
    }
}

new OtherClass();
$ node sample
42
Hello world!

我怀疑在加载模块时这些行的运行顺序会引起混淆。 Node 的模块加载代码将按照遇到的顺序运行每一行。

【讨论】:

  • 不要告诉我在 JavaScript 中将所有代码放在同一个文件中是个好主意吗?
  • 并且全局变量的定义肯定在任何一个类之前运行,这很容易检查。
  • 不,绝对不是!但正如其他人所指出的,使用global 作为存储东西的地方也不是一个好主意。我的回答只是证明你正在尝试做的事情在最基本的情况下可以正常工作。单个文件消除了模块加载的复杂性,表明一个构造函数可以访问global对象。
  • ...我的问题不是它是否适用于最基本的情况。我知道它有效。我什至列出了它所在的环境。对我没有帮助的情况没有帮助。
  • 如果您不得不处理使用 global 的遗留代码,我会同情您。如果我的回答不能帮助确定问题,请随时更新问题,详细说明如何加载不同的 JS 模块,我可以更新我的以尝试匹配。
【解决方案2】:

问题在于 Mocha 无法在其测试中访问全局变量。我找不到 与此行为相关的错误,但至少是 person with the same problem

由于全局变量只在测试中使用,我得到了一个简单的解决方案:

global.MyObject= new MyClass();

module.exports.MyObject = MyObject;

而这个在测试中:

before(() => {
    global.MyObject = require('./mock/my-class').MyObject;
});

添加 TODO 可能是个好主意,这样您就可以不时地重新审视这个问题,以防 Mocha 工作人员修复它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 2017-05-18
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    相关资源
    最近更新 更多