I wrote a class module that has async methods, and now im trying to chain the methods using .then()
the scope of 'this' changes somewhere along the line and i then have to bind the function back to its instance to get the proper scope back.
class.js
class Asdf {
#asdf;
constructor(){
this.#asdf = 'asdf'
}
async funcOne(){
// h.funcOne().then // works fine
return this.#asdf
}
async funcTwo(a){
// .then(h.funcTwo) // this.funcThree becomes undefined?
// where does the scope change??
var x = await this.funcThree(a)
return x
}
async funcThree(a){
return a
}
}
module.exports = Asdf
script.js
var h = new (require('./class.js'));
h.funcOne().then(h.funcTwo) // scope is changed, code breaks, claiming undefined
h.funcOne().then(h.funcTwo.bind(h)) // works because we re-bind the scope
// Where and Why does the Scope Change??
Why does the scope change using .then? and can I prevent it?
This is not about scope in the literal definition. It's about the binding of the this
value when a function is called in different ways.
The issue is that when you pass h.funcTwo
as a function argument, it reaches into the h
object and grabs a reference to funcTwo
and passed JUST a reference to that function that will be called without any reference to h
and will not be associated with h
at all. That means that this
inside that call to funcTwo()
will be undefined
because it wasn't called as h.funcTwo()
.
So, as you found, can use .bind()
to instead pass a function stub that will call it as h.funcTwo()
rather than just as funcTwo()
.
You can see a simpler example here:
"use strict";
const x = {
f: function() { console.log(this)},
g: "it's me",
};
x.f(); // properly logs the x object
let y = x.f;
y(); // logs undefined since the binding to x was lost
// and f() was called all by itself without
// any reference to x
let z = x.f.bind(x); // properly logs the x object
z();