Can't access settings in registered event callback function

I’m writing a plugin intended to execute logic after a change to the front matter. I would like this logic to use information from settings to determine its execution path. The challenge I’m having is I don’t know how to access settings from a callback function.

A stripped down version of the plugin (that shows my challenge) is below.

interface MyPluginSettings {
	booleanSetting: boolean;
}

const DEFAULT_SETTINGS: MyPluginSettings = {
	booleanSetting: false
}

export default class MyPluginPlugin extends Plugin {
	settings: MyPluginSettings;

	public doWork() {
		// ERROR GETS THROWN HERE...
		// TypeError: Cannot read properties of undefined (reading 'settings')
		console.log(this.settings.booleanSetting);
	}

	public async onload() {
		await this.loadSettings();
		this.addSettingTab(new MyPluginSettingTab(this.app, this));
		this.app.workspace.onLayoutReady(this.doWork);
		this.registerEvent(this.app.metadataCache.on("changed", this.doWork));
	}

	public onunload() {
	}

	public async loadSettings() {
		this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
	}

	public async saveSettings() {
		await this.saveData(this.settings);
	}
}

I believe the issue is a limit on my own understanding of how callbacks work relative to how a object gets constructed. Unfortunately, I’ve not had any luck Googling (or using ChatGPT) to help.

Any assistance would be appreciated.

Update

I don’t know if what I’m doing is the best practice but, I was able to work around the problem by:

  1. Introducing another member variable, self, which I set to null
  2. Setting self to this in the onload method
  3. Using self to access settings

Updated code is below.

export default class MyPluginPlugin extends Plugin {
	settings: MyPluginSettings;
    self = null;  // new code

	public doWork() {
		console.log(self.settings.booleanSetting);  // updated code
	}

	public async onload() {
		this.self = this;  // New code
        await this.loadSettings();
		this.addSettingTab(new MyPluginSettingTab(this.app, this));
		this.app.workspace.onLayoutReady(this.doWork);
		this.registerEvent(this.app.metadataCache.on("changed", this.doWork));
	}
}

This is one of the most confusing aspects of JavaScript in my opinion.
JavaScript’s this works differently from this in C++ or self in Python.
Take a look at this post on StackOverflow:

or this tutorial page:

You can avoid this issue by using bind:

this.registerEvent(this.app.metadataCache.on("changed", this.doWork.bind(this)));

Another solution is defining doWork as an arrow function:

public doWork = () => console.log(this.settings.booleanSettings)

because arrow functions have no this: