first off to give some context of my situation...I've got a library containing a few models etc for my application, then an electron application which adds some UI, the electron app also loads a custom JS file which allows for adding additional logic.
On my Workspace model I'm using the singleton pattern (I know, I know) to store an instance of the workspace. When the app starts up, it's loading the workspace, then calls document.head.appendChild to load my custom script.
In the custom script, I'm requiring that same model library to get my Workspace class. However, Workspace.instance is returning null despite it definitely being not null before.
By contrast, if before loading the script I do global.workspace = workspace, then the script can access the instance fine. So can anyone tell me what's going on? As far as I understood, static properties and methods have essentially global scope, though this seems to suggest otherwise.
In my library:
export default class Workspace {
static instance: Workspace = null;
startupData: any;
constructor(startupData: any) {
this.startupData = startupData;
Workspace.instance = this;
}
}
In my app:
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);
In my custom 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.
That would be fine if using native modules, but I suspect you're using a bundler of some kind (Webpack, etc.). I suspect you're ending up with two different copies of your module loaded: One as part of the initial app bundle, then another loaded natively by the browser's module handling. Since those are separate modules (as far as the browser knows), you end up with two copies of Workspace
and thus two copies of its instance
property.
Depending on the bundler, there's usually a way to tell it to handle this, but the details vary by bundler.
But, answering the question of scope: A public static property like your instance
can be accessed anywhere its containing class (constructor function) can be accessed, because it's a property of that function object.
If by "scope" you meant "lifecycle," the static property is created when the class (constructor function) is created, and released once the class (constructor function) is released (or the property is removed from it via delete
).
Just as a side note, your Workspace
class isn't a singleton. Every time you do new Workspace
, you'll create a new instance (and overwrite the previous value that was in Workspace.instance
. To make it a singleton, you need to add a check to the constructor:
constructor(startupData: any) {
if (Workspace.instance) {
return Workspace.instance; // Return the singleton
}
this.startupData = startupData;
Workspace.instance = this;
}
Or better yet, make your singleton more idiomatically (from a JavaScript perspective) by simply directly exporting an object:
export default const workspace = {
// ...properties and methods...
};
or if you need class
features like private fields:
export default const workspace = new class Workspace {
// ...constructor (if desired), properties, and methods...
}();