After several attempts I have resorted to asking something that is possibly very identifiable by its error.
Implementing notifications with Pusher I have run into a problem. I can't assign the receiving information to my model in Vuejs. I currently have my code as follows:
var channel = pusher.subscribe('my-channel.' + this.notificationId);
channel.bind('postulation', function(data) {
console.log(data)
})
I can pass it without any problem to the console receiving the notification. But... if I want to assign to a model, like this:
var channel = pusher.subscribe('my-channel.' + this.notificationId);
channel.bind('postulation', function(data) {
console.log(data)
this.notifyCount ++
})
It doesn't work, in fact, if I try to print, someone console.log(this.notifyCount)
tells me undefined
why I can't assign information to my model?
It should be said that it only happens within channel.bind()
How do I solve it?
The problem is in the variable
this
, which is not what you think.What you should know about
this
this
(aka "the context") is a special identifier within each function and its value depends on how the function is called, not how/where/when it was defined. It is not affected by lexical scopes like other variables (except for arrow functions , see below). Here are some examples:To learn more about
this
, take a look at the MDN documentation .How to refer to the
this
correctDo not use
this
Actually, you don't want to access
this
in particular, but the object referenced by . That's why an easy solution is to simply create a new variable that also refers to that object. The variable can have any name, but the most commonly used areself
andthat
.Since it
self
is a normal variable, it obeys lexical scope rules and is accessible within the callback . This also has the advantage that you can access the valuethis
of the callback itself (which as we have seen depends on where and how the function is called).Explicitly set the
this
callback - part 1It may seem like you don't have control over the value of
this
because its value is set automatically, but that's not the case.Each function has the
.bind
[docs] method , which returns a new functionthis
bound to a value. The function has exactly the same behavior as the one it calls.bind
, justthis
set by yourself. No matter how or when that function is called,this
it will always refer to the value passed to it.In this case, we are setting the
this
callback to the value ofthis
the callback itselfMyConstructor
.Note: When setting the context in jQuery,
jQuery.proxy
[docs] is used instead of.bind
. The reason for this is that you don't need to store the reference to the function when you unbind the callback from the event.jQuery
handle this internally.ECMAScript 6: Using arrow functions
ECMAScript 6 introduced arrow functions , which can be thought of as lambda functions . They do not have their own link
this
. Instead,this
the scoped visibility of the function is searched, just like a normal variable. That means you don't have to call.bind
. That's not the only special behavior they have, check out the MDN documentation for more information.Explicitly set the
this
callback - part 2Some functions/methods that accept callbacks also accept a value that you must refer to
this
within the callback . This is basically the same as doing bind yourself, but the function/method does it for you.Array#map
[docs] is such a method. Your signature is:The first argument is the callback and the second is the value to refer to
this
. Here is a small example:Note: It is usually the function/method documentation that mentions whether or not you can pass a value for
this
.$.ajax
For example, the jQuery method [docs] describes an option calledcontext
:Free translation:
Common problem: Using object methods as callbacks /event handlers
Another common manifestation of this problem is when an object method is used as a callback /event handler. Functions are first-class citizens in JavaScript, and the term method is just a colloquial term for a function that is a value of an object property. But that function doesn't have a specific binding to the "containing object".
Consider the following example:
The function
this.method
is assigned as a handler for the click event, but if you click ondocument.body
the value that will appear in the log, it will beundefined
because within the event handlerthis
it refers todocument.body
, not to the instance ofFoo
.As I mentioned at the beginning, what is meant by
this
depends on how the function is called and not how it is defined .If the code looked like the following, it would be more obvious that the function does not have an implicit reference to the object:
The solution is the same as mentioned above: If available, use
.bind
to explicitly bindthis
to a specific value.Or explicitly call the function as a "method" of the object, using an anonymous function as a callback /event handler while assigning the object (
this
) to another variable:Or use an arrow function:
With information from this StackOverflow answer in English.
The problem is that if you use
bind
without indicating the context the value ofthis
will bepusher
Solution:
To indicate the context you must pass it like this:
References:
this
context