javascript - 理解 JS 中静态属性的作用域
问题描述
首先给出我的情况的一些背景......我有一个包含一些模型等的库,用于我的应用程序,然后是一个添加一些 UI 的电子应用程序,电子应用程序还加载一个自定义 JS 文件,它允许添加额外的逻辑。
在我的 Workspace 模型上,我使用单例模式(我知道,我知道)来存储工作区的一个实例。当应用程序启动时,它正在加载工作区,然后调用 document.head.appendChild 来加载我的自定义脚本。
在自定义脚本中,我需要相同的模型库来获取我的 Workspace 类。但是,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
解决方案
当应用程序启动时,它正在加载工作区,然后调用 document.head.appendChild 来加载我的自定义脚本。
如果使用本机模块,那会很好,但我怀疑您正在使用某种捆绑器(Webpack 等)。我怀疑您最终会加载两个不同的模块副本:一个作为初始应用程序包的一部分,然后另一个由浏览器的模块处理本地加载。由于这些是单独的模块(据浏览器所知),因此您最终会得到其属性的两个副本Workspace
,因此也有两个副本。instance
根据捆绑器的不同,通常有一种方法可以告诉它处理这个问题,但细节因捆绑器而异。
但是,回答范围问题:像您这样的公共静态属性instance
可以在任何可以访问其包含类(构造函数)的地方访问,因为它是该函数对象的属性。
如果“范围”是指“生命周期”,则静态属性是在创建类(构造函数)时创建的,并在释放类(构造函数)时释放(或通过 删除属性delete
)。
顺便说一句,您的Workspace
班级不是单身人士。每次执行时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...
}();
推荐阅读
- kubernetes - 运行 kubectl 作业时是否可以发送文件?
- bokeh - 将解析的字符串值转换为浮点数
- progress-bar - 禁用材质 UI
动画 - ios - 输入密码时键盘上方出现黑条
- python - pip install selenium - '隧道连接失败:403 Forbidden'
- sql-server - 检查谁/何时更新 SQL Server 中的列
- internet-explorer - 如何从 maven 原型运行 Serenity BDD 简单项目(serenity.version=2.0.40)
- jenkins - 如何检测jenkins管道项目(groovy脚本)中人工触发的触发原因?
- macos - Automator 快速操作将图像保存到同一文件夹中
- c# - 我可以使用 Dapper 映射具有多个关系的 SQL 表吗?