I haven't used Javascript in a long time and have been refreshing myself on it today. One thing that always got me was the this keyword. I know in jQuery event handlers, such as the click event, this refers to the element that fired the event. How is this passed to the function that I give it as a callback even though my function has no arguments?
Given the following code:
$("tr.SummaryTbRow").data("Animating", false);
$("tr.SummaryTbAltRow").data("Animating", false);
$("tr.SummaryTbRow").click(function () {
if ($(this).data("Animating") == false) {
if ($(this).next(".Graph").css("display") == "none") {
$(this).data("Animating", true);
//Part I am questioning.
setTimeout(function () {
$(this).data("Animating", false);
}(this), 550);
$(this).next(".Graph").slideRow('down', 500);
}
else {
$(this).data("Animating", true);
$(this).next(".Graph").slideRow('up', 500);
}
}
});
I am trying to figure out how to pass the element table row with class SummaryTbRow to my setTimeout call back function. Does jQuery pass this in a similar fasion to what I am doing with my anonymous call back function? Does my this inside the function refer to the this I pass in?
I know I could just do:
setTimeout(function (element) {
$(element).data("Animating", false);
}(this), 550);
But I want to figure out how jQuery is able to pass this to my call back function even though my function takes 0 arguments.
To answer you last question, you may pass the receiver of your choice to a function in javascript using for exemple call :
someFunction.call(someObject);
Inside someFunction, this will be someObject.
In your case, what you seem to want is
setTimeout(function (element) {
$(element).data("Animating", false);
}, 550, this); // this will be passed as element to the callback
or (more compatible)
var _this = this;
setTimeout(function () {
$(_this).data("Animating", false);
}, 550);
Short answer:
You can set this on a function by using the function's .call() and .apply() methods.
Long answer:
The this variable on any function is similar to the arguments variable (which is probably something you didn't know about). It's set when the function is called and is an artifact of how the function is called. To explain, let me start with a demonstration of arguments. Consider:
myFunction = function () {
return arguments.length;
};
Now let's look at a couple calls to myFunction:
myFunction(); //is 0
myFunction(null); //is 1
myFunction(undefined); //is 1
myFunction(0, 0, 0, 0, 0); //is 5
As you can see, the value of arguments.length is not dependent on how or where we wrote the function, but on how we called the function. The same is true of the this variable (otherwise known as the "calling object"). There are exactly 3 methods for setting the calling object (there's a sort-of 4th in ES5, but we'll ignore that):
You can set it by calling the function using dot-notation (e.g. something.myFunction())
You can set it by using the function's .call() or .apply() methods (e.g. myFunction.call(someObject))
If it's not set using method #1 or #2, it will default to the global object (e.g. window)
So most people are used to method #1. If you assign your function as a property of an object, then call the function using the object and dot-notation, then the object gets set as this. Like so:
var myFn = (function () { return this.x });
var myObj = {
x: 1,
y: myFn
};
myObj.myFn(); //is 1
But we can also use method 2 if myFn isn't a property of the object we want to call it on but the object follows the correct form for myFn to be able to act on it (see: duck typing):
var myOtherObj = {
x: 2
}
myFn.call(myOtherObj); //is 2
myFn.apply(myOtherObj); //is 2
myFn.apply({ x : 3}); //is 3
Pretty cool, eh? This is how jQuery does it. When they execute your callback, they do so using .apply(event.target) (setting this to the event's target object). They do it in a more complex manner because of their callbacks framework, but the idea is there.
Anyway, I wouldn't be offering a long answer if I didn't toss in an explanation of method #3, which drives some people totally insane: What happens if you don't set the calling object?
Because all global variables are implicit properties of the global object, you get some interesting effects from method #3. Such as:
var x = 4;
myFn(); //is 4
But most of the time you're not lucky enough to have your global object meet the requirements the function has for its calling object, so usually it just results in an error and a lot of frustration.
Probably more than you were looking for, but hopefully you're now much more informed on the calling object and its wily ways.
You can call a function using fn.call or fn.apply both of which take a context argument which is used for this.
Apply, call and bind methods serve for that purpose. In your case you just write:
setTimeout(function() {
$(this).data("Animating", false);
}.bind(this), 550);
Related
Language: Javascript
Operating System: Ubuntu 14.04
Browser: Tested in Chromium, Chrome, Firefox.
Background
I'm making a HTML5 Canvas game that has various collectable items. The superclass for these items is Collectable, which has a render() function:
Collectable.prototype.render = function(){
// renders the collectables
}
There are different subclasses of Collectable, all of which delegate render() to the superclass. For example:
var Heart = function(x, y) {
Collectable.call(this, x, y);
}
Heart.prototype = Object.create(Collectable.prototype);
I instantiate my collectables by first creating an array containing all of my collectables:
var collectables = [];
var numOfEach = 5;
// IIFE so as to not pollute global scope
(function() {
for (var i = 0; i < numOfEach; i++) {
// TODO: make this cleaner
var heart = new Heart(100, 200);
collectables.push(heart);
var gemBlue = new GemBlue(100, 200);
collectables.push(gemBlue);
var gemOrange = new GemOrange(100, 200);
collectables.push(gemOrange);
}
})();
Then in my game loop file, I have a renderEntities() function that repeatedly calls individual render methods on my objects:
function renderEntities() {
// render my other objects
...
// render collectables
collectables.forEach(function() {
// test what 'this' is bound to
console.log(this);
// call render method
this.render();
});
}
...however in this case this is bound to window and therefore this.render is not a function.
Question
How do I bind this to each individual element of my collectables array?
My research
I've read the documentation for the bind function, but I'm afraid I can't work out how this would be applied with forEach() and my anonymous function.
I then found this existing question which explained how forEach takes an optional parameter to set this. After reading the documentation on forEach I tried the following with unsuccessful results:
collectables.forEach(function() {
// test what 'this' is bound to
console.log(this);
// call render method
this.render();
}, this);
...which obviously had the same effect of setting this to the global object.
collectables.forEach(function() {
// test what 'this' is bound to
console.log(this);
// call render method
this.render();
}, collectables);
...this got me a little closer, as this is bound to the collectables array as a whole, but obviously this.render is still not a function. I can't see what argument I can use here in forEach to bind this to each element of the array.
I have a feeling that after typing all this out the answer will be very simple. I'm relatively new to the concept of this so go easy on me!
I haven't found another question that answers this for me, or at least one that I'm able to understand given my level of knowledge. For example, I have considered the following questions:
Calling a class function in forEach: how Javascript handles “this” keyword.
The invocation context (this) of the forEach function call
Passing scope to forEach
If I understand correctly, you are looking to get the object associated with each collectable item. In this case, simply pass an argument for the forEach loop. In this case, I've called that argument theObj but perhaps theCollectable or even just c would be more accurate.
collectables.forEach(function(theObj) {
// test what 'this' is bound to
console.log(theObj);
// call render method
theObj.render();
});
Update: the this you are passing in the forEach call is passing the current value of this to the loop. At that point, this is executed within the scope of window, and that's why this is window. You do not need to pass this if you do not wish to refer to the window, and since window is global you really have no need to pass this at all, so I've removed it from the suggested answer.
Update: the MDN is a great resource for JavaScript documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
The .forEach() facility passes three arguments to your callback function:
The current element of the array;
The index into the array;
The array itself.
Thus:
collectibles.forEach(function(collectible) {
// the parameter "collectible" will be the
// current array element
});
There's really no need to bind this, but if you absolutely wanted to you could:
collectibles.forEach(function callback(collectible) {
if (this !== collectible)
callback.call(collectible, collectible);
else {
// body of function
}
});
Up until now, I've always used var self = this before creating a function that would need access to its parent. However the bind() method seems like a more appropriate way to do so and I'm exploring that option, along with the apply() and call() methods.
This is what I came up with to compare all three:
jsFiddle
(function(){
this.say = function(text){
console.log(text);
}
this.run = function(){
console.clear();
setTimeout(function(){
this.say('bind');
}.bind(this), 1000);
setTimeout(function(){
this.say('call');
}.call(this), 1000);
setTimeout(function(){
this.say('apply');
}.apply(this), 1000);
}
this.run();
})();
But the script leaves me with some questions:
Why don't the call() and apply() methods respect the timeout like the bind() method does and which one should I use?
Is there any difference between the following syntaxes which behave similarly:
setTimeout( function(){ this.say('bind'); }.bind(this) , 1000);
setTimeout( (function(){ this.say('bind'); }).bind(this) , 1000);
setTimeout( (function(){ this.say('bind'); }.bind(this)) , 1000);
You're missing a key point here (but the key point is very obfuscated in documentation).
You know whenever you write a function like this:
function something() {
// ... whatever
}
It's just a function reference sitting there by itself. It hasn't been called yet.
When you write something like this:
(function something() {
})()
Or this:
function something() { ... }
something();
You've now called the function. Those are two very completely different concepts.
In the first one where the function is just sitting there without having been called, it's referred to as a function reference, and that's exactly what .bind returns: a function reference.
.call and .apply return the return value of whatever function, in the new context. So in fake JavaScript la-la land, it would look something like this:
function() {
}.bind(this)
// returns a function reference: function() { }
Whereas:
function() {
return 'hello';
}.call(this)
// returns hello... NOT A FUNCTION REFERENCE!
You see...
You would probably never do something like this:
function hello() {
return true;
}
setTimeout(hello(), 100);
You'd get an error: setTimeout expected a Function, and it received a Boolean, or something like that.
^ That's not a very semantic error, but it's an error nonetheless.
But, what you would do is something like this:
function hello() {
return true;
}
setTimeout(hello, 100);
See the difference? That last example is okay, because you passed in a function reference.
Because internally, setTimeout does something like this:
window.setTimeout = function(callback) {
// a bunch of other stuff, and...
callback();
};
As far as your second question goes...
Those are pretty much all equivalent. Closures make sense though whenever you're declaring variables that you don't want to give other objects access to.
To help you understand closures a little bit, let's pretend we're not even talking about JavaScript.
In math, you know how you can do something like a + b * c?
Well, when you group them by parentheses, it kind of changes the behavior: (a + b) * c.
Now, obviously that's not quite related to JavaScript in the sense that in JavaScript we're not worried about order of operations (unless you're actually doing math in JavaScript), but the whole idea is that those parentheses just act as a container (what we call a closure) for whatever is inside of it.
So when you put a function inside parentheses, you're just hiding that function from the outside world, but it can still return stuff, and it can still have access to parent scopes (like window, for example).
A cool example:
var name = (function(name) {
return name
})(function() {
return 'Jane';
}());
console.log(name); // => Jane
Both .call and .apply execute the functions on which they are called immediately. What this means is that in those cases you are passing the result of call or apply on your anonymous function to setTimeout and that result is undefined because those functions don't return anything.
bind on the other hand returns a new function, which you are then correctly passing to setTimeout. To get call and apply to behave similarly, move them inside the anonymous function:
setTimeout(function(){
this.say.call (this, 'call');
}, 1000);
for example.
Afaik those are equivalent.
I know how to use the methods for changing the context of a function/method call: apply, bind, call. My question is this, is there a way to check if a function/method has already had its context set?
// given
var beta;
function alpha () {
return this;
}
function isContextSet (fn) {
/* check for context binding on fn */
}
beta = alpha.bind("hello");
isContextSet(alpha); // returns false
isContextSet(beta); // returns true
I think I know the answer to this already but thought I would ask anyway, if for no other reasons than: 1. confirm my assumption, or 2. learn something. I'm sure that I am not the first to ask this question but I have had no idea on how to actually find an answer since all I get are responses to how to use: .apply(), .call(), or .bind().
No.
Actually, it's incorrect to refer to binding as "changing" the context. What it does is transform one function into another one which calls the first with a particular context.
Functions can be bound in many ways. For instance, I could bind it myself:
function bind(fn,ctxt){
return function(){
fn.apply(ctxt,arguments);
};
}
Or, I could bind it with Function.prototype.bind, or a shim that does the same thing, or underscore's _.bind. I could bind it to initial arguments in addition to the context. In each case, there's no way to tell what has happened without essentially actually executing the function.
Binding is just one of many ways to transform one function into another one. I could also transform a function to execute one second from now, or be executed twice. There is nothing magic about binding; it just creates a new function based on the old one. There is no special variable called [[bound_to]] set on the function that you might be able to examine (unless you use your own custom implementation of bind, as another answer suggests). There's no post facto way to determine how the function was transformed.
The closest I can imagine coming is checking the possibly bound function against an unbound version and see if they are equal.
function log_this(){console.log(this);}
var bound_func=log_this.bind(my_var);
console.log(log_this===bound_func); // FALSE
What could be done is something like this:
function f(context, whatever) {
if(this !== context) {
//context has been changed
}
}
var y = f.bind(thingy);
y(otherThingy, something);
You could also have a custom bind function and have a sort of a hack like this:
function bind(func, context) {
var newFunc = func.bind(context);
newFunc._this = context;
return newFunc;
}
function checkContext(func, context) {
return func._this !== context;
}
I think this is interesting question for those how love JavaScirpt and I hope this is response what you are looking for:
var isContextSet = function (fn) {
var testThis = {}; //unique object for testing what is this inside fn
return fn.call(testThis) !== testThis;
}
I try to "set" this inside fn: fn.call(testThis); and if that function returned reference to newly created object (testThis) then it is not binded. I hope you get it :)
EDIT:
This works when fn retuns this (as shown in question). Otherwise you can not define isContextSet properly.
I study JavaScript Proxy Pattern, but I still do not get, where I can benefit from it. I would therefore like to provide you with two examples and kindly ask you to point at the difference between them.
Please, take a look at the code below:
What is the difference between the two addEventListener calls? One of them calls handleDrop in regular way. The other uses Proxy Pattern.
What will I gain using Proxy pattern approach?
I tested both functions, and they both call handleDrop successfully.
DndUpload.prototype.buildDropZone = function ()
{
var self = this,
this.dropZone.addEventListener('drop', function (e) { self.handleDrop.call(self, e) }, false);
this.dropZone.addEventListener('drop', self.handleDrop, false);
DndUpload.prototype.handleDrop = function (e)
{
alert("test");
...
};
}
You can provide me with good reference which contains very clear explanation of Proxy Pattern in JavaScript.
So what you're describing in your example isn't so much a demonstration of the Proxy pattern as much as a demonstration of confusion regarding the "calling object" and how it works in JavaScript.
In JavaScript, functions are "first-class." This essentially means that functions are data just like any other data. So let's consider the following situation:
var fn = (function () { return this.x; }),
a = {
x : 1,
fn : fn,
},
x = 2,
nothing = (function (z) { return z; });
So, we have an object a, which has two properties: fn and x. We also have variables x, fn (which is a function returning this.x), and nothing (which returns whatever it gets passed).
If we evaluate a.x, we get 1. If we evaluate x, we get 2. Pretty simple, eh? Now, if we evaluate nothing(a.x), then we get 1. That's also very simple. But it's important to realize that the value 1 associated with the property a.x is not in any way connected to the object a. It exists independently and can be passed around simply as a value.
In JavaScript, functions work the same way. Functions that are properties (often called "methods") can be passed as simple references. However, in doing so, they can become disconnected from their object. This becomes important when you use the this keyword inside a function.
The this keyword references the "calling object." That's the object that is associated with a function when that function is evaluated. There are three basic ways to set the calling object for a function:
If the function is called using the dot operator (e.g. a.fn()), the relevant object (in the example, a) is set as the calling object.
If the function is called using the function's call or apply properties, then you can explicitly set the calling object (we'll see why this is useful in a second).
If no calling object is set through method 1 or method 2, the global object is used (in a browser, this is typically called window).
So, back to our code. If we call a.fn(), it will evaluate as 1. That's expected because the this keyword in the function will be set to a due to the use of the dot operator. However, if we call simply fn(), it will return 2 because it is referencing the x property of the global object (meaning our global x is used).
Now, here's where things get tricky. What if you called: nothing(a.fn)()? You might be surprised that the result is 2. This is because passing a.fn into nothing() passes a reference to fn, but does not retain the calling object!
This is the same concept as what's going on in your coding example. If your function handleDrop were to use the this keyword, you would find it has a different value depending on which handler form you use. This is because in your second example, you're passing a reference to handleDrop, but as with our nothing(a.fn)() example, by the time it gets called, the calling object reference is lost.
So let's add something else to the puzzle:
var b = {
x : 3
};
You'll note that while b has an x property (and therefore satisfies the requirements for fn's use of this), it doesn't have a property referencing fn. So if we wanted to call the fn function with its this set to b, it might seem we need to add a new property to b. But instead we can use the aforementioned apply method on fn to explicitly set b as the calling object:
fn.apply(b); //is 3
This can be used to "permanently" bind a calling object to a function by creating a new function "wrapper." It's not really permanently binding, it's just creating a new function that calls the old function with the desired calling object. Such a tool is often written like so:
Function.prototype.bind = function (obj) {
var self = this;
return function() {
return self.apply(obj, arguments);
};
};
So after executing that code, we could do the following:
nothing(a.fn.bind(a))(); //is 1.
It's nothing tricky. In fact, the bind() property is built into ES5 and works pretty much like the simple code above. And our bind code is actually a really complicated way to do something that we can do more simply. Since a has fn as a property, we can use the dot operator to call it directly. We can skip all the confusing use of call and apply. We just need to make sure when the function gets called, it gets called using the dot operator. We can see how to do it above, but in practice, it's far simpler and more intuitive:
nothing(function () { return a.fn(); })(); //is 1
Once you have an understanding of how data references can be stored in closure scope, how functions are first-class objects, and how the calling object works, this all becomes very simple to understand and reasonably intuitive.
As for "proxies," those also exploit the same concepts to hook into functions. So, let's say that you wanted to count the number of times a.fn gets called. You can do that by inserting a proxy, like so (making use of some concepts from our bind code from above):
var numCalls = (function () {
var calls = 0, target = a.fn;
a.fn = (function () {
calls++;
return target.apply(a, arguments);
});
return (function () {
return calls;
});
}());
So now, whenever you call numCalls(), it will return the number of times a.fn() was called without actually modifying the functionality of a.fn! which is pretty cool. However, you must keep in mind that you did change the function referenced by a.fn, so looking way back to the beginning of our code, you'll notice that a.fn is no longer the same as fn and can't be used interchangeably anymore. But the reasons should now be pretty obvious!
I know that was basically a week of JavaScript education in a couple pages of text, but that's about as simple as it gets. Once you understand the concepts, the functionality, usefulness, and power of many JavaScript patterns become very simple to understand.
Hope that made things clearer!
UPDATE: Thanks to #pimvdb for pointing out my unnecessary use of [].slice.call(arguments, 0). I have removed it because it's, well, unnecessary.
Basically, passing self.handleDrop directly is functionally equivalent to passing the following function:
function() {
return self.handleDrop.apply(this, arguments);
}
because everything is passed through to the original function:
The this value
The arguments
The return value
With this in mind, compare your functions as follows:
function(e) { self.handleDrop.call(self, e) }
function() { return self.handleDrop.apply(this, arguments); }
The difference with your proxy way is:
It doesn't pass the return value through.
It doesn't pass all arguments through (only the first, e)
It doesn't pass the this value through, but uses a predefined one: self.
Now, the first two items don't make a difference here, because addEventListener doesn't care about the return value, and it also only passes one argument anyway.
But the third item is important: it sets a different this value in the function. By default, this is the element you bind the event to (it it set by the browser). Using the proxy way, you can set another this value.
Now, in your snippet it is not fully clear why you're setting a prototype function each time buildDropZone is called. Usually you define prototype functions only once. But when your handler handleDrop is called using the proxy way, this refers to the DndUpload instance, which is consistent with prototype functions in general.
Consider the code below:
function printThis() {
console.log(this);
}
var someObject = {
performTest : function() {
var self = this;
someOtherObject.higherOrderFunction(printThis);
someOtherObject.higherOrderFunction(function(){printThis.call(self)});
}
}
var someOtherObject = {
higherOrderFunction : function(f) {
f();
}
}
What will someOtherObject.higherOrderFunction(printThis) return?
How about someOtherObject.higherOrderFunction(function(){printThis.call(self)})
The answer to the first question depends on who and how you call someObject.performTest(). If I just call someObject.performTest() from a global context, it will probably print Window.
The second one will always print the someObject instance no matter what.
The closures or 'proxy pattern' as you call it comes in handy when you want to control exactly the execution context of a function.
Note: this in javascript does not behave like it does in other languages(in Java for example).
Question 1
I've just started learning jQuery and one thing that puzzles me is function() with a parameter in it, ie: function(e).
[Example 1]
$("#rating a").click(function(e){
// stop normal link click
e.preventDefault();
}
What is e in function(e)?
[Example 2]
$.post("test.php", function(data) {
alert("Data Loaded: " + data);
});
How do you know what data is? I assume data is different from e in example 1.
I'm confused as to why function() is different in different senarios...
Question 2
Since we are talking about basic jQuery, here's another jQuery question. What is the difference between this and $(this)?
[Example 3]
$(document).ready(function() {
// use this to reset several forms at once
$("#reset").click(function() {
$("form").each(function() {
this.reset();
});
});
[Example 4]
$("a").hover(function(){
$(this).parents("p").addClass("highlight");
},function(){
$(this).parents("p").removeClass("highlight");
});
});
function(e) -> this is passing in the event object as a parameter. Without e you just don't have access to the event object.
"this" is the object in context to whatever you're doing. If you wrap "this" like $(this) then you have access to all the extensions that jQuery gives you. To be more clear, "this" is usually a DOM object, $(this) is a jQuery object.
You can declare functions in one of two ways in JavaScript.
This way:
function MyFunction() {
//Functiony stuff
}
And this way:
var MyFunction = function() {
};
Using the second method, you can then pass that function to other functions as an argument. Those functions that receive it can then provide it arguments. If you don't define those arguments in your function, then you can't access them. Here's a bit more:
var MyFunction1 = function(message) {
alert(message);
};
var MyFunction2 = function(alertFunction) {
if(alertFunction != null)
alertFunction("Here's another method!");
};
//You can then call MyFunction and pass it arguments, even if that argument is a function.
MyFunction2(MyFunction1);
Had you not defined the message variable in MyFunction1, you would have never gotten the message that was passed to it via MyFunction2. Hope I didn't make that more complicated than it needed to be... Basically, you can pass functions around, and if you don't provide the variables that methods will pass to it, you can't use them. This is what you're doing when you say something like:
$("MySelector").click(function(e) {
//Stuff here
});
You're sending an anonymous function to the click function. If you don't provide for the variables that it will pass to you, you can't use them.
Once I realized you could do this a long time ago, it changed the way I wrote JavaScript quite a lot. I'm sure it'll probably do the same for you.
In your first example:
$("#rating a").click(function(e){
// stop normal link click
e.preventDefault();
}
e is the event object. It's preventDefault method prevents the default for the used event. In this case click will not have any effect. It is used like return false; but some browser may have different actions. This works for all.
As for this vs $(this)
While inside a function, if this refers to the DOM element that triggered the event, $(this) is still the DOM element that triggered the event, only it is wrapped in a jQuery element by wrapping a $() around it.
check this question on SO jQuery: What's the difference between '$(this)' and 'this'?
function(x) { ... }
is an anonymous function (i.e. you're not giving it an explicit name) being passed as an argument to those functions (in your examples, passed as an argument to click() and post()). This is usually used for callbacks. The click() function does some stuff and then later on down the line, your anonymous function is invoked as a response to something (a click event, in this case).
The x indicates that this anonymous function takes one parameter and its name within the function's scope will be x. You can name it whatever you want (in one example it's e, in another it's data, but in neither case does it have to use those names). In general, you could make it take as many parameters as you want, like function(x, y, z) { return (x + y + z); } but, in the examples you gave, jQuery is looking for a certain prototype.