The function doSomethingElse
in this example fails to execute since its this
has been rebound to window
or global
(if in Node) due to a contextless call inside app.populateDatabase
.
Is there any way to avoid this without referencing app
inside every function?
loadDatabase
function executes a callback according to a logic statement, if an imaginary database didn't exist, it populates it after loading, then the populateDatabase
executes the callback it has been provided.
I cannot rebind the onLoaded
argument to app
since I don't know where it comes from, and the bind/apply/call abstraction overuse creates quite a mess.
var app = {};
app.loadDatabase = function(onLoaded) {
// If database already exists, only run a callback
var callback = onLoaded;
// If database doesn't exists, populate it, then run a callback.
if (!databaseExists) {
callback = this.populateDatabase.bind(this, onLoaded);
}
this.database = new sqlite.Database("file.db", function(error) {
if (error) { ... }
callback();
})
}
app.populateDatabase = function(onPopulated) {
// Contextless call here. <--------
onPopulated();
}
app.doSomethingElse = function() {
// this != app due to contextless call.
this.somethingElse();
}
app.run = function() {
// Load the database, then do something else.
this.loadDatabase(this.doSomethingElse);
}
app.run();
Just replace this.loadDatabase(this.doSomethingElse);
with this.loadDatabase(() => this.doSomethingElse());
. This way you create a new arrow function but then doSomethingElse
is called with the right this
context.
You could also do .bind
but I recommend the arrow function. Here with bind
: this.loadDatabase(this.doSomethingElse.bind(this))
In general consider to move to promises & maybe async functions. Then do this:
this.loadDatabase().then(() => this.doSomethingElse());
or better with an async function:
await this.loadDatabase();
this.doSomethingElse();