Reputation: 12539
I have an object which has two functions within it, and as I guessed each one has a different value for this
:
custom_controls : {
play_pause : function () {
console.log(this); // object
videoPlayer.getIsPlaying(function (video_is_playing) {
if (video_is_playing) {
console.log(this); // window
videoPlayer.pause(true);
} else {
videoPlayer.play();
}
});
}
},
Then the function is invoked like this:
custom_controls.play_pause()
I've heard that the way you invoke a function denotes the value of this
.
So my question is: What is happening here? What kind of function invocations am I using? And how does each one affect this
?
Upvotes: 0
Views: 117
Reputation: 63
Each function is actually executed within a context. That context is denoted as the current this
for which you call the function.
Given your code:
If you call custom_controls.play_pause()
you are saying "Take the field of the object custom_controls named play_pause and execute it within the context of the object custom_controls".
Later on calling videoPlayer.getIsPlaying()
means pretty much the same. Except you're giving it a callback function. How that callback function is executed later on depends on how videoPlayer.getIsPlaying
is implemented.
If I have to guess I'd say that getIsPlaying has a callback.call(window, video_is_playing)
somewhere in it.
call
is a method of all function objects in javascript.
There are a few ways to work around this "issue" if you want to reference a this
in some callback.
var self = this;
call_me_maybe(function() {
console.log(this); //the this that call_me_maybe chose to call your function with
console.log(self); //the this from the upper scope
});
or if you don't care about the object in which context call_me_maybe
will call your function:
call_me_maybe((function(){
console.log(this); //the this from the upper scope
}).bind(this));
What bind
does is it returns a wrap[per of the function which will always be called in the context of the object to which it is bound.
bind
can also bind arguments as well as the this
object for the function, creating a sort of curry.
Upvotes: 1
Reputation: 243
Your first this is referring to play_pause
.
Your second this could either be referring to the Window or your videoPlayer object. In JavaScript, closures and regular functions are 'generally' attached to window
, and calling this returns window
. In certain cases, e.g. if you attach a function to the click handler of an HTML element, this refers to the element...
element.onclick = function(){
this // -> element
}
But generally if you just create a function()
, or have an anonymous one like yours this
refers to window
.
function hello(){
this // -> window
}
Upvotes: 1
Reputation: 27823
When calling obj.func()
, this
inside the function will be equal to obj
. If there is no obj
, the global object (window
) is used instead. Or if you are running in Strict Mode, undefined
is used.
The first log is your object because you call the function like this:
custom_controls.play_pause() // custom_controls will be 'this'
The second log is window because the function passed as parameter to getIsPlaying
is not called with any this
:
videoPlayer.getIsPlaying = function(callback) {
callback(); // this inside callback will be window
}
You can control what the value of this
will be when you invoke a function by using call
or apply
. You can create a new function which will always have the this
value set to whatever you want by using the bind
function:
videoPlayer.getIsPlaying(function (video_is_playing) {
if (video_is_playing) {
console.log(this); // my obj
videoPlayer.pause(true);
} else {
videoPlayer.play();
}
}.bind(this)); // magic!
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Upvotes: 2
Reputation: 7452
When you call videoPlayer.getIsPlaying
it accepts a callback fn. Callback is invoked directly like cb()
and hence the context is global (window).
To achieve the callback happening in context of your object. You can use
var fn = cb.bind(customControl);
videoPlayer.getIsPlaying(fn);
As a rule of thumb when a function is called like object.function
this is set to object
. If function is called directly, this
is set to window. Function.bind
return a function after binding object
(this value) optionally along with parameters.
Read: MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Upvotes: 0
Reputation: 7010
this
refers to the "proprietary" of the function, or the object from the function is a method of.
When you define a basic function, the "proprietary" is the page (or the window) itself.
You can check the callback
documentation for workarounds
Upvotes: 0
Reputation: 12805
The this
that you've discovered is the object is what you would expect because the function is operating on that object.
I'm not familiar with your videoPlayer
, but as the value of this
is the "window", I would imagine that either A the video player is a function of the browser itself, or B its scope was not properly closed.
Upvotes: 0