了解 JS 中静态属性的范围

Understanding the scope of static properties in JS

首先介绍一下我的情况...我有一个库,其中包含一些适用于我的应用程序的模型等,然后是一个电子应用程序,它添加了一些 UI,电子应用程序也会加载允许添加额外逻辑的自定义 JS 文件。

在我的工作区模型上,我使用单例模式(我知道,我知道)来存储工作区的实例。当应用程序启动时,它正在加载工作区,然后调用 document.head.appendChild 来加载我的自定义脚本。

在自定义脚本中,我需要相同的模型库来获取我的工作区 class。但是,Workspace.instance 返回 null,尽管它之前肯定不是 null。

相比之下,如果在加载脚本之前我执行 global.workspace = workspace,则脚本可以正常访问实例。所以谁能告诉我这是怎么回事?据我了解,静态属性和方法本质上具有全局范围,尽管这似乎表明并非如此。

在我的图书馆中:

export default class Workspace {
    static instance: Workspace = null;

    startupData: any;

    constructor(startupData: any) {
        this.startupData = startupData;
        Workspace.instance = this;
    }
}

在我的应用程序中:

import Workspace from 'mymodels';

const workspace = new Workspace(startupData);
global.workspace = workspace;
console.log(Workspace.instance);    //Returns my workspace instance

const script = document.createElement('script');
script.onload = showUI;
script.src = 'file:///' + workspace.startupData.logic;
document.head.appendChild(script);

在我的自定义脚本中:

const mymodels = require('mymodels');

console.log(mymodels.Workspace.instance);    //Returns null
console.log(global.workspace);               //Returns my workspace instance

When the app starts up, it's loading the workspace, then calls document.head.appendChild to load my custom script.

如果使用本机模块就好了,但我怀疑您正在使用某种捆绑器(Webpack 等)。我怀疑您最终加载了两个不同的模块副本:一个作为初始应用程序包的一部分,另一个由浏览器的模块处理本地加载。由于这些是独立的模块(就浏览器而言),您最终会得到 Workspace 的两个副本,因此 instance 属性.

的两个副本

根据捆绑器的不同,通常会有一种方法告诉它处理这个问题,但细节因捆绑器而异。


But,回答范围问题:像你的 instance 这样的 public static 属性 可以在任何包含 class(构造函数)可以访问,因为它是该函数对象的 属性。

如果“作用域”指的是“生命周期”,那么静态 属性 在 class(构造函数)创建时创建,并在 class(构造函数)创建后释放功能)被释放(或通过 delete 从中删除 属性)。


请注意,您的 Workspace class 不是单身人士。每次执行 new Workspace 时,都会创建一个新实例(并覆盖 Workspace.instance 中的先前值。要使其成为单例,您需要向构造函数添加检查:

constructor(startupData: any) {
    if (Workspace.instance) {
        return Workspace.instance; // Return the singleton
    }
    this.startupData = startupData;
    Workspace.instance = this;
}

或者更好的是,通过简单地直接导出一个对象,使您的单例更加地道(从 JavaScript 的角度来看):

export default const workspace = {
    // ...properties and methods...
};

或者如果您需要 class 私有字段等功能:

export default const workspace = new class Workspace {
    // ...constructor (if desired), properties, and methods...
}();