I'm looking into the code of the jQuery ToolTip plugin(hereinafter Tooltip), and have a noticed a behaviour I don't fully understand.
Tooltip binds a mouseover function like so:
.mouseover(save)
When called in this way, this variable is HtmlDivElement.
I tried changing the mouseover to this:
.mouseover(function(e){save(event)})
Since I'm looking for the MouseEvent. However, now this variable is Window.
I found a way to baypass this and get the HtmlDivElement by using this line of code:
.mouseover(function(e){save(this, event)})
and using this as a replacment for the this inside the function.
My question is - why is the save function losing it's scope when being called inside an anonymous function inside the mouseover binding?
The value of this is established upon each function call. When your anonymous function calls that "save" function, it's not doing anything to establish what this should be, so it's the default value: the global object ("window").
You can do this:
.mouseover(function(e){ save.call(this, e); })
to make this take on the value you need. The this value in the handler will be arranged by the framework, so by using .call() you're passing it on to the "save" function.
To repeat: in JavaScript, this is not determined by static structure of the code. Instead, it depends on the situation of each individual function call. That means that for any function, no matter how it's declared, the value of this may be a complete surprise on any given function call.
Related
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.
I am learning JavaScript and becoming confused by the logic of the code examples. From codecademy. Why are there function set-ups in function calls?
I'm quite confused. I am moving from a simplified C-like langue.
The JavaScript example
var main = function(){
$('.article').click(function(){
$('.description').hide();
$(this).children('.description').show();
});
};
My understanding:
- main is a function name with a return type of var.
$('.article') is a element/object/or class object.
.click() is a call to a member function
But:
???:
.click(function(){
$('.description').hide();
$(this).children('.description').show();
});
This seems to be a newly on the spot created function to run When/If click() is activated or run.
The way I used to think is like this:
var *p_obj = $('.article');
var *p_obj = $('.description');
var do_click()
{
p_obj2.hide();
p_obj.children(p_obj2).show();
}
var main(){
p_obj.click(do_click);
}
Function main() looks at p_obj and calls click().
Click() evaluates to true/false and run the pointer_to function do_click().
Function do_click() looks at the p_obj2 and calls hide(), which performs an action of hiding the p_obj2.
Function do_click() also looks at p_obj and uses children to scope focus to p_obj2, then it runs show(), which preforms an action of displaying p_obj2.
I do realize my C-like example is wrong and odd. I realize my terminology is wrong or otherwise used incorrectly.
The way this design looks seems like I must write extended functionality on-the-spot for every call to .click(), so if-then .click() is run on 3 different items, I'm creating different extended functionality for each object. But I would normally create a single function that varies it's internal execution based on the object or condition click() calls it by.
This set-up seems alright if the code a relatively simple or short, but on-the-spot functional seems like overworking for longer code and code where the functionality repeats but the objects change.
Am I thinking about JavaScript functions with-in functions correctly and is this a design goal of the langue to add long repeating extended functions with-in functions?
Here, you should understand 2 things:
passing functions as arguments
anonymous functions
The first concept is particulary important because callbacks are popular in JavaScript, so let me explain it for callbacks. Imagine we have 2 functions getStuffFromWeb and processStuff. You probably expect that they are used like this:
var result = getStuffFromWeb();
processStuff(result);
But the issue here is waiting for getStuffFromWeb may take some time (the server is busy), so instead they are usually used in a "when you finish, call this function" manner, which is:
var getStuffFromWeb = function(params,callback) {
...
callback(result);
};
getStuffFromWeb(someParams,processStuff);
Well, in fact the structure of getStuffFromWeb will be different, most likely something like this:
var getStuffFromWeb = function(params,callback) {
requestObject.make_request(params)
.onSuccess(callback);
};
So when getStuffFromWeb is called, it starts to listen to response while the code after getStuffFromWeb(someParams,processStuff); goes on evaluating. When the response comes, it calls the callback function to process the data further using the procedure we have defined (processStuff).
The second concept is rather simple: you may of'course write smth like
var processStuff = function() {...};
var getStuffFromWeb = function(params,callback) {
requestObject.make_request(params)
.onSuccess(callback);
};
getStuffFromWeb(someParams,processStuff);
but if you use processStuff only once, why define a named function? Instead, you can just put the very same expression inside the onSuccess param like this:
var getStuffFromWeb = function(params) {
requestObject.make_request(params)
.onSuccess(function() {...});
};
getStuffFromWeb(someParams);
This looks exactly like if we took the value of processStuff and put it directly to the onSuccess's argument (and that's called anonymous function). And also we got rid of an extra argument of getStuffFromWeb.
So basically that's it.
Simple answer is that the second argument of click() requires a callback function.
This can be a named function passed as reference as in your p_obj.click(do_click); example or it can be an anonymous function with self contained logic. Anonymous functions are very common in javascript
It's the same thing just with 2 different ways of declaring the callback.
Note that the only time you would return anything from an event handler function would be to return false which effectively prevents the default browser event (url opening from href or form submit for examples) and stops event propagating up the DOM tree
main is a function name with a return type of var.
No. main is a variable which is assigned an anonymous function. The function name would go between the keyword function and the () containing the argument list.
It has no return statement so it returns undefined.
$('.article') is a element/object/or class object.
It is a call to the function $ with one argument. The return value is a jQuery object.
.click() is a call to a member function
Pretty much. In JavaScript we call any function that is the value of a property of an object as method.
This seems to be a newly on the spot created function
function () { } is a function expression. It creates a function, exactly like the one used to assign a value to main earlier. This question is worth reading for more on the subject.
When/If click() is activated or run.
The click function is called immediately. The new function is passed as an argument.
The purpose of the click function is to bind a click event handler so that when a click event hits the element later on, it will trigger the function passed as an argument.
I do realize my c -like example is wrong and odd. I realize my terminology is wrong or otherwise used incorrectly.
Leaving aside vagaries of syntax. The main difference here is that the click event handler function is that the event handler function is stored in an intermediary variable.
You can do that in JavaScript just as easily, and then reuse the function elsewhere in the code.
var main = function(){
function show_specific_description() {
$('.description').hide();
$(this).children('.description').show();
}
$('.article').click(show_specific_description);
show_specific_description.call($(".article").last()[0]);
};
main();
is this a design goal of the langue to add long repeating extended functions with-in functions?
No. Passing a function expression as an argument is a convenient way to be more concise when you don't want to reuse the function. It's not the only way to pass functions about.
main is currently a function.
It is possible to be overwritten (even to a different type). var is not the return type, it's a statement that main is a variable.
All values should be declared as variables, within the highest scope you intend them to be used (in JS, scope typically means functions, not blocks).
You have the right idea, suspecting that the function gets passed in, and called at a later point in time (and this is actually one of the harder parts for people to get, coming from certain other languages). You'll see this behaviour all through JS.
One key thing to keep in mind in this language (you haven't hit it yet, but you will) is that JS is lexically scoped.
function getInnerX () {
var x = 5;
function getX () {
return x;
};
return getX;
}
var x = 10;
var getX = getInnerX();
console.log(getX()); // 5
The function getX inside of getInnerX has access to the references around it, at the point where it's defined (not where it's called), and thus has live access to the inner x, even if its value changes over time.
This will be another important piece of understanding what you see going on in the language, especially in the case of callbacks.
I'm reading a great article on this in JavaScript. The author says that the following code is bad:
Cart = {
items: [1,4,2],
onClick: function () {
// Do something with this.items.
}
}
$("#mybutton").click(Cart.onClick);
He says that the click event doesn't know about the Cart object when calling onClick, therefore this.items won't be the [1,4,2] array that I expect it to be.
The author goes on to say that this code creates a closure and fixes it but I don't understand how the following code fixes the problem.
$("#mybutton").click(function () { Cart.onClick() });
1) In what context (if not Cart) does this thing we're in if we use the first example.
2) Why does the second example fix the problem?
Some good detail about this is given in "How does the “this” keyword work?"
But, the important part is that the value of this is determined when and by how the function is invoked.
By passing the method itself as an argument, accessing it from an object and invoking it become separate acts. This separation is how it loses track of the object it came from – Cart.
The invocation is performed by jQuery. And, for event handlers, it determines the value of this to be the referenced element (matched by $("#mybutton"), in this case):
When jQuery calls a handler, the this keyword is a reference to the element where the event is being delivered; [..]
Rather than passing the method itself, this provides an alternate, wrapping function for jQuery to invoke instead. Within that function's body, accessing the method and invoking it are combined in a single statement.
Having them combined, the language itself determines the value of this as the (last) Object before the function – Cart.
this is always context of the function call. This is why $("#mybutton").click(Cart.onClick); sends mybutton object to the function as this. In the second example you call Cart.onClick() in its own context; this is Cart.
You can fix first example like this: $("#mybutton").click(Cart.onClick.bind(Cart)); to force context to Cart object.
If you try <button onclick="Cart.onClick()... then this is windows object.
I hope my explanation helps you.
Currently this function works:
$("#email_address_input").on('focusout', function(){
emailValidationCheck($(this));
});
function emailValidationCheck(e){
...
}
So basically, if the email address input element is focused out, then an anonymous function runs, which calls the declared function emailValidationCheck (and of course, that declared function takes as an argument the email address input element).
That anonymous function feels redundant. All it does is call the declared function, so it seems to me like it should be taken out.
So, what I tried to do was call the declared function directly upon the event firing, as opposed to calling the anonymous function, which in turn calls that declared function. Like this (warning, it doesn't work as expected):
$("#email_address_input").on('focusout', emailValidationCheck($(this)));
Question: How can I get this to work? Or is the original answer best practice? Basically what I am trying to do is: when the focusout event fires off on the specified element, I want to execute the emailValidationCheck function, where the passed in argument is the element where this all this stuff is happening on.
Thanks!
You don't need to use anonymous functions as callbacks for events. You can easily call a defined function without using the () precursor (because including that will essentiall pass the return value of emailValidationCheck to the callback, rather than the function reference itself). For example:
$("#email_address_input").on('focusout', emailValidationCheck);
Now, your emailValidationCheck function will receive the event in the e variable that you define in the function constructor.
Because the function has been bound as a callback, $(this) is also available within it. For example:
function emailValidationCheck(e)
{
console.log( e ); // logs the event
console.log( $(this) ); // logs the jQuery object that lost focus
}
jsFiddle Demo
That's not how javascript works. The .on() function wants a function as a parameter. You can either pass an anonymous function or the name of a function. As soon as you put () at the end, it executes the function inline and passes the result to the .on() function.
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.