What does the 'function' do in the following?
$('.event-row').on('mouseover',function(){
arc.event_handler.event_row_over();
});
$('.event-row').on('mouseover',arc.event_handler.event_row_over );
There's a very important difference.
The first one will call the function with the context its this value as the event_handler object.
The second one will call the function with the context its this value as the DOM element to which the handler is bound.
So the first one preserves the expected calling context this value, which may be required by the function.
In the first case with the anonymous function this inside that function is bound to the DOM element that caused the event. This is a convention that is common in browsers and also done when binding events natively. When calling arc.event_handler.event_row_over(); however, this is re-bound to arc.event_handler inside event_row_over; as it's called as an object method and in such a case this points to the object on which the method was called. The method will be called without any arguments.
In the second case you register the function arc.event_handler.event_row_over for the event. When called jQuery sets this to the related element so inside event_row_over, this points to that element. arc.event_handler is not available in there unless there is some other variable that points to it. jQuery also passes the event object as the first argument so the method is called with that argument.
Usually object methods expect this to be their object, so in almost every case you want to use the anonymous function to wrap the call. In case the element matters, pass this as an argument to the method.
Another way, without an anonymous function, would be using the bind() method every function has:
$('.event-row').on('mouseover', arc.event_handler.event_row_over.bind(arc.event_handler));
However, only modern browsers support this natively.
In the first case you are enclosing the function call in an anonymous function.
In the second case you are just assigning the function pointer..
First off, it seems like there is an extra dot in there.. arc.event_handler.event_row_over.(); should probably be just arc.event_handler.event_row_over();
And all the anonymous function does is it calls a member function named event_row_over of the arc.event_handler object; and it doesn't return anything.
The 'function' keyword will creates a new closure and encapsulate the scope. Good article on closures https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures.
The first case, you have an additional function wrapper. This is useful when you want to do something else before calling the real event handler 'arc.event_handler.event_row_over()' for example you may do something like below:
$('.event-row').on('mouseover',function(){
doPreEventHandling();
arc.event_handler.event_row_over();
doPostEventHandling();
});
On the other hand you may even extract that annonymous function to be a named function and call as below:
var eventHandler = function(){
doPreEventHandling();
arc.event_handler.event_row_over();
doPostEventHandling();
};
$('.event-row').on('mouseover', eventHandler);
All above will be just similar in behavior, but more wrapper functions you have more abstraction you gain. But it will compromise performance and sometimes readability.
The context/scope of the function will not be the same.
Also, with the second one,
$('.event-row').on('mouseover',arc.event_handler.event_row_over );
you're getting the event object as an argument.
Related
MY ISSUE
I've been learning the basics of AJAX from two different internet sources. In the multi-step process of sending an async HTTP request, there's one small inconsistency in how the .onload property is called on the XHR request object and then set to 1) an anonymous function or 2) a callback (??? that's what I think MDN says).
1ST APPROACH
the .onload property is called on the ourRequest object and this is set to an anonymous function:
ourRequest.onload = function() {
// the code goes here
}
2ND APPROACH
the .onload property is called on the asyncRequestObject object and this is set to the name of the function (a callback??):
function handleSuccess () {
// the code goes here
}
asyncRequestObject.onload = handleSuccess;
MY QUESTION(S)
What's the difference between how the 1st and the 2nd approach work?
And then, is there any reason to use the 1st approach over the 2nd approach?
A function declaration creates a (hoisted) variable in the current scope, that has the same name as the function, and whose value is a reference to that function.
A function expression simply evaluates as a reference to that function.
So the primary difference is that where you use handleSuccess, you can continue to reference the function for other purposes elsewhere.
What's the difference between how the 1st and the 2nd approach work?
The difference is that the first function is an anonymous function expression while the second is a function with a name. Both are event handlers for the "load" event of the XMLHttpRequest .
And then, is there any reason to use the 1st approach over the 2nd approach?
If you don't plan to reuse your handler somewhere else then you don't need to declare your function with a name.
It is no different than any other programming practice. Use a variable/constant when a value is called multiple times, otherwise use a literal.
I am trying to pass function reference as event handler in jQuery. I would like to use a shorthand like in the simple example below...
$("a").click(console.debug.bind(undefined,this));
...rather than passing explicitly the whole function body:
$("a").click(function() {
console.debug(this)
});
Moreover, I would like to access elements selected by jQuery in my shorthand function (and pass them as a parameter). In other words: I expect to have a result of $("a") as a this (or any other code that will retrieve the result).
So far I've tried:
var a = function() {
console.debug(this);
};
var b = console.debug.bind(undefined,this);
$("a").click(function() {console.debug(this)}); // prints link
$("a").click(a); // prints link
b(); // prints Window
$("a").click(console.debug.bind(undefined,this)); // prints Window & jQuery.Event
Here is the fiddle:
https://jsfiddle.net/hbqw2z93/1/
My questions are:
Is it possible to use such construction and meet all requirements, without definition of additional variables - just one line as shown above?
Is it possible to access jQuery's selection result using described approach?
Why in the given scope this becomes 'merged' Window and jQuery.Event object?
You already using it, aren't you? :) It's limited, but it works in your own fiddle
jQuery will pass event object to your specified function. You can use function bind to pass that as an argument (you already have this working in your fiddle)
It doesn't. See what's happening:
jQuery passed one argument to click handler function - event object. You pass console.debug.bind(undefined, this) as a handler function so jQuery will call it with one argument.
Then, when you are binding you are asking to use 'undefined' as a 'this' object inside the function and sending an extra argument - 'this', which is a Window at this scope because you are binding at the highest level.
So when actual click happens, jQuery calls console.debug with two parameters - Window object that was bound during click() and jQuery event that is always passed to click handler. console.debug() can accept and display multiple objects, which is exactly what you see in the developer console.
The first parameter of bind is the new context to use for this. By passing undefined you are essentially not passing the first parameter.
The second and further parameters are passed into the function as the first values.
Note also that this when in the global scope, refers to the window object.
So here, b...
console.debug.bind(undefined,this);
is identical to...
function(){ console.debug(window); }
..since you're passing this (which is window) as the first parameter to debug.
By default, when you attach an event to the element, this will automatically point to the element which caught the event, so bind shouldn't even be necessary, which is why $("a").click(a); worked without using bind.
In a codebase I see bind used to make bound copies of functions on the prototype, used as callbacks for DOM events.
Why might this idiom be used, rather than, for example, using the methods on the prototype directly?
Does this offer some benefits in terms of memory consumption/the ability to free memory use when events are unbound from DOM events?
function F() {
var onFoo = this._onFoo.bind(this); // Why?
document.getElementById('foo').onClick(onFoo);
}
F.prototype._onFoo = function () { /*...*/ }
The issue is that event handlers set their own value for this when they call the callback. That value will typically be related to the event handler, not to the object that the method is bound to. For example, in your example:
document.getElementById('foo').onClick(myObj.myFunc);
The this pointer in myFunc will be set to the DOM element that had the event handler attached (in this case, the foo element). But that isn't myObj so myFunc in that case could not access any of it's own instance variables via the this pointer (the normal way that methods access their instance data).
So, if you have a method that wants to access it's own instance data when it is called directly by an event handler, you have to do something other than just pass the method to the event handler. There are a couple ways to work around this issue.
One way of doing so it so use .bind() which returns a new stub function who's function is to set this before calling your function like this:
document.getElementById('foo').addEventListener('click', myObj.myFunc.bind(myObj));
In this case .bind() actually returns a new stub function who's function is to set the value of this to myObj before it calls myFunc.
You could also do that manually yourself like this:
document.getElementById('foo').addEventListener('click', function(e) {
myObj.myFunc();
});
But, as you can see, .bind() provides a shortcut that takes less code (which is why it was invented).
A potential disadvantage to using .bind() in some cases is that you may no longer have access to the value of this that the caller of your callback would have set itself because .bind() threw that value away and replaced it with your own. In the event handler example above, this is not an issue because the original source of the event can be accesses via the e argument that is passed to the event handler so it is not lost if you need it.
I am aware of no meaningful difference in memory consumption or garbage collection between the two methods above. Both create a new function that is used to call the original and control the value of this when calling the original function. Both will have the same garbage collection lifetime.
It appears that one thing that is confusing you is that objects in Javascript are assigned or passed by pointer (some call it by reference, but that has some connotations that don't apply here so I'll use the phrase by pointer).
var x = {};
x.myFunc = function() {console.log("hello");};
x.myFunc(); // generates "hello" in the console
var t = x.myFunc; // save reference to the function that x.myFunc currently points to
delete x.myFunc; // remove property myfunc from the x object
t(); // generates "hello" in the console
t() still works event after x.myFunc has been removed because both t and x.myFunc had a reference (or pointer) to the same function. Doing a delete x.myFunc simply removed the myFunc property from the x object. The function that x.myFunc points to will only be "freed" by the GC when there are no other references to it. But, there is another reference to that function in t, so it is not freed and t() can use it for as long as t exists.
I've seen it done differently in code out there, but is there any benefit or reason to doing a (blank params) .call / .apply over a regular () function execution.
This of course is an over-simplified example
var func = function () { /* do whatever */ };
func.call();
func.apply();
VERSUS just the simple parenthesis.
func();
Haven't seen any information on this anywhere, I know why call/apply are used when params are passed.
When you call a method with func();, this variable inside the method points to window object.
Where as when you use call(...)/apply(...) the first parameter passed to the method call becomes this inside the method. If you are not passing any arguments/pass null or undefined then this will become global object in non strict mode.
Yes, there is an important difference in some cases. For example, dealing with callbacks. Let's assume you have a class with constructor that accepts callback parameter and stores it under this.callback. Later, when this callback is invoked via this.callback(), suddenly the foreign code gets the reference to your object via this. It is not always desirable, and it is better/safer to use this.callback.call() in such case.
That way, the foreign code will get undefined as this and won't try to modify your object by accident. And properly written callback won't be affected by this usage of call() anyways, since they would supply the callback defined as an arrow function or as bound function (via .bind()). In both such cases, the callback will have its own, proper this, unaffected by call(), since arrow and bound functions just ignore the value, set by apply()/call().
I'm reading javascript the good parts, and the author gives an example that goes like so:
['d','c','b','a'].sort(function(a,b) {
return a.localeCompare(b);
});
Which behaves as expected.
Now I have tried to do something like this - which is the next logical step:
['d','c','b','a'].sort(String.prototype.localeCompare.call);
And that fails with an error:
TypeError: object is not a function
Now I left wondering why...
Any ideas?
call needs to be bound to localeCompare:
['d','c','b','a'].sort(Function.prototype.call.bind(String.prototype.localeCompare));
The reason you are having a problem is that you are passing sort Function.prototype.call. As you may know, when no this is otherwise provided, it will be the global object (window in browser environments). Thus, when sort tries to call the function passed to it, it will be calling call with this set to the global object, which in most (all?) cases is not a function. Therefore, you must bind call so this is always localeCompare.
The reason it doesn't work is that String.prototype.localeCompare.call returns a reference to Function.prototype.call not to String.prototype.localeCompare as you might think.
You're passing a reference to the call function without retaining any relationship to the localeCompare method you intend it to be called upon. So sort will invoke the function referenced byString.prototype.localeCompare.call, but it will invoke it in the global context, not as the method of some function object.
As #icktoofay pointed out, you need to bind the call function to localeCompare. Here's a much oversimplified demonstration of how this is done without the bind method:
function simpleBind(fn, _this) {
return function() {
return fn.apply(_this, arguments);
}
}
['d','c','b','a'].sort(simpleBind(Function.prototype.call,
String.prototype.localeCompare));
Ok, solved it!
this does the trick:
['d','x','z','a'].sort(String.prototype.localeCompare.call.bind(String.prototype.localeCompare))
Cause when you think about it the sort function actually calls apply on call so it needs to be bound to the string object in order to execute in scope.
^_^