This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the javascript category.
Last Updated: 2024-10-12
The following code failed, saying that this.createUserAccount
is not a
function (even though the function was defined on the same object). The issue was that
this
became another object during the time the callback was called:
window.SemicolonAndSons = {
createUserAccount(email),
videoReady(video) {
video.bindEvent("conversion", function(email) {
this.createUserAccount(email) // fails
})
},
}
Two fixes are available:
First, rewrite with arrow function (since arrow functions cause this
to be
preserved as the object it referred to outside the arrow function (here thanks
to the way videoReady uses the method syntax it will be the SemicolonAndSons
object)
windown.SemicolonAndSons = {
// Note that if object syntax were used (videoReady: {} then `this` would be
// undefined)
videoReady(video) {
video.bindEvent("conversion", (email) => {
this.createUserAccount(email)
})
},
}
Fix two: keep the normal function, but bind
that function to this
video.bindEvent("conversion", function(email) {
this.createUserAccount(email)
}.bind(this))
--
Here's a general example that should make things clearer
function multiply(p, q, callback) {
callback(p * q);
}
let user = {
x: 2,
y :3,
userMultiply: function() {
// Inside a method call, x and y will always refer to
// the user's data, assuming the method gets called on the `user` object
multiply(this.x, this.y, function(sum) {
// HOWEVER, inside this callback, which gets executed outside of
// the user object in the top-level `multiply` function, `this` will not
// be the `user`
console.log(sum); // Prints 6, as expected, since it is working on the args passed to multiply: p and q
console.log(this === window); // Prints true // i.e. this is not the user, but the window
})
}
}
// Now for something really weird:
let outerMultiply = user.userMultiply;
outerMultiply()
// Sum is NAN - i.e. x and y are not defined since this function is no longer being // called on the user!
// vs.
user.userMultiply()
// Sum is 6 - i.e. x and y ARE defined when called like this.