I am having a hard time figuring out how to reassign a variable to a new function.
I have two anonymous functions that are assigned to variables and I want "first" to assign itself to "after" after it is called once.
When using .toSource in Firefox it seems like it is definitely reassigning first to after, but the "first in the click handler is still referencing or calling the first that was created at runtime.
Why is this?
JS
var after = function() {
alert("AFTER");
}
var first = function() {
alert("FIRST");
//alert(first.toSource());
first = after;
}
$(".order").click( first );
HTML
<button type="button" class="order">Order</button>
http://jsfiddle.net/E2R2R/2/
Following up on #MichaelGeary s answer, if you want to make the function work by referencing like that, put your function call inside an anonymous function:
$(".order").click( function() {
first();
});
Demo: http://jsfiddle.net/E2R2R/4/
When you make this call:
$(".order").click( first );
you are using the value of first at the time of this call. Its value at that time is what is passed into the click() function.
Changing the value of the first variable later won't affect this.
Another way to look at it: think about the code inside jQuery's click() method. It doesn't know that you used the first variable in your call. The only information it has is the function that first refers to at the time of the call.
See #tymeJV's answer for a way to do what you want. Note what's different about it: the function you're passing into .click() (the anonymous function) doesn't have to change. When that function calls first(), it always uses the current value of that name.
Related
I have the following function
function hello() {
alert("hi!");
}
Take this piece of code:
var elem = document.getElementById("btn");
elem.onclick = hello;
My question might be a bit hard to understand, so bear with me:
What EXACTLY differentiates THIS piece of code from a normal call, or what makes this piece of code require a reference to the function variable rather than a regular call? (hello();)
How can I know where I'm supposed to give a reference to the function, and when I'm supposed to actually call it?
Well, the onclick property expects a reference to a function, for it to execute when the element is clicked. Normally it's either:
element.onclick = funcRef;
or
element.onclick = function () {
funcRef();
};
(but of course, it's best to use addEventListener and attachEvent)
Notice how both of them are references to functions, not calling.
When something expects a reference, you don't call it...you assign a reference to it (first example).
When you want to specifically call a function, you call it with () (second example). But notice how in the second example, there's still a reference to a function that's assigned to onclick - it's just an anonymous function.
Probably the more important part:
Some people think you want to do this:
element.onclick = funcRef();
But that immediately executes the function (because of the ()), and assigns its return value to onclick. Unless the return value is a function, this isn't what you want.
I think the moral of the story is that when you want/need something to execute right now, you call the function. If the function is wanted for later use or needs stored, you don't call it.
Do you want it to execute NOW? Then call it.
a=hello() means "Call hello() ASAP, and set its return value to a".
On the other hand, a=hello means "a is an alias for hello. If you call a(), you get the same results as calling hello()"
You use the latter for callbacks, etc, where you want to tell the browser what you want to happen after an event occurs. For example, you may want to say "call hello() when the user clicks" (as in the example). Or, "When the AJAX query returns a result, call the callback() function on the returned data".
How can I know where I'm supposed to give a reference to the function, and when I'm supposed to actually call it?
Do you need the function to run now?
Than add the () to execute it
Do you need to function to be referenced so it is called later?
Do not add the ().
Pretty much all statements in JavaScript have a return value. Unless otherwise specified, functions in JavaScript will return undefined when called. So, the only context in which it would make sense to call your function in this assignment statement if it were to return a function:
function hello() {
return function() {
alert("hi!");
}
}
elem.onclick = hello();
A reference to your function is needed somewhere no matter how it gets called. The difference here is that you are not explicitly calling the hello function. You are assigning a reference to that function to the elem DOM node's onclick event handler so that when onclick is fired for that Node, your function gets called.
hello() means you call that function, which means the function will be executed directly.
while when you have elem.onclick = hello, this is called a callback. Where hello doesn't get executed directly but only when a certain event is fired (in this case when there's a click on the element)
I have the following function
function hello() {
alert("hi!");
}
Take this piece of code:
var elem = document.getElementById("btn");
elem.onclick = hello;
My question might be a bit hard to understand, so bear with me:
What EXACTLY differentiates THIS piece of code from a normal call, or what makes this piece of code require a reference to the function variable rather than a regular call? (hello();)
How can I know where I'm supposed to give a reference to the function, and when I'm supposed to actually call it?
Well, the onclick property expects a reference to a function, for it to execute when the element is clicked. Normally it's either:
element.onclick = funcRef;
or
element.onclick = function () {
funcRef();
};
(but of course, it's best to use addEventListener and attachEvent)
Notice how both of them are references to functions, not calling.
When something expects a reference, you don't call it...you assign a reference to it (first example).
When you want to specifically call a function, you call it with () (second example). But notice how in the second example, there's still a reference to a function that's assigned to onclick - it's just an anonymous function.
Probably the more important part:
Some people think you want to do this:
element.onclick = funcRef();
But that immediately executes the function (because of the ()), and assigns its return value to onclick. Unless the return value is a function, this isn't what you want.
I think the moral of the story is that when you want/need something to execute right now, you call the function. If the function is wanted for later use or needs stored, you don't call it.
Do you want it to execute NOW? Then call it.
a=hello() means "Call hello() ASAP, and set its return value to a".
On the other hand, a=hello means "a is an alias for hello. If you call a(), you get the same results as calling hello()"
You use the latter for callbacks, etc, where you want to tell the browser what you want to happen after an event occurs. For example, you may want to say "call hello() when the user clicks" (as in the example). Or, "When the AJAX query returns a result, call the callback() function on the returned data".
How can I know where I'm supposed to give a reference to the function, and when I'm supposed to actually call it?
Do you need the function to run now?
Than add the () to execute it
Do you need to function to be referenced so it is called later?
Do not add the ().
Pretty much all statements in JavaScript have a return value. Unless otherwise specified, functions in JavaScript will return undefined when called. So, the only context in which it would make sense to call your function in this assignment statement if it were to return a function:
function hello() {
return function() {
alert("hi!");
}
}
elem.onclick = hello();
A reference to your function is needed somewhere no matter how it gets called. The difference here is that you are not explicitly calling the hello function. You are assigning a reference to that function to the elem DOM node's onclick event handler so that when onclick is fired for that Node, your function gets called.
hello() means you call that function, which means the function will be executed directly.
while when you have elem.onclick = hello, this is called a callback. Where hello doesn't get executed directly but only when a certain event is fired (in this case when there's a click on the element)
I am pretty new to javascript, and i am facing some problem understanding why my first code is not working as expected. I have read a few articles on "this", but it didn't help.
var user_obj = {
some_func : function () {
alert("hello");
}}
First code:
Here i am attaching an event listener to some element called elem. The attached function is a property of user_obj, but when i execute it, it gives me error "TypeError: this.some_func is undefined". My doubt is when i am using bind to explicitly bind this to user_obj, why is it giving this error.
document.getElementById("elem").addEventListener("click",(function () {this.some_func.bind(user_obj)})());
Second Code:
This works as expected.
document.getElementById("elem").addEventListener("click",this.some_func.bind(user_obj));
Thanks for the help.
bind() change the value of this inside the function, not outside.
In your first example the anonymous function use this to refer to global object.
If you want the anonymous function uses this to refers to user_obj you need to bind the anonymous function to user_obj, not some_func(), also because some_func() doesn't use this, so there is no need to bind it.
Look at the example: it prints the value of this in the anonymous function, first time binding it to user_obj, second time without binding
var user_obj = {
some_func : function () {alert("hello");}
};
document.getElementById("elem").addEventListener("click",(function () {console.log(this)}.bind(user_obj))());
document.getElementById("elem").addEventListener("click",(function () {console.log(this)})());
<div id="elem"></div>
Your second example works also without the bind(), because again it changes the value inside the function, where this isn't used. But since in your second example the call to the function isn't in an anonymous function, the value of this doesn't change to global object
BTW, it is getElementById(), not getElementByID() (please notice the d of Id)
I have a JS object called 'avatar' with a create function that generates a button on an HTML page and sets a few attributes.
I want to set an onmouseover on the button that calls a function within the avatar object so I have written:
this.create = function(){
this.button = document.createElement("BUTTON");
this.text = document.createTextNode(this.name);
this.button.appendChild(this.text);
document.body.appendChild(this.button);
this.button.style.background=this.color;
this.button.addEventListener("mouseover", this.randomMove());
}
However, the function randomMove is executed immediately and does not wait for the button to be mouseovered. Subsequent mouseovers do nothing.
You need to pass it a function body, not what the function returns. In your case, the code evaluates this.randomMove() and assigns the returned result to the mouseover event handler. This is how it should look:
this.button.addEventListener("mouseover", this.randomMove);
See this simple example to easily understand what's going on: http://jsfiddle.net/f8tm4jq3/
Like Andy mentioned, you need to pass the function reference (without parenthesis), not function expression (with parenthesis) as the argument to addEventListener.
Thanks for your help.
As it turns out what I was really looking for was bind.
this.button.addEventListener("mouseover",this.randomMove.bind(this));
This bound the function call to a method belonging to this object. So even though the HTML generated lives outside the scope of the object instance, the function call remembers which instance it should make the call to.
Thanks again
Ben
I'm having an issue with a function I'm calling (using jQuery).
My issue is that when I attempt call a function within another function, that first one is not being called. However, when I place the contents of the failed function into the one calling said failed function, the code executes fine. I'll show you what I'm talking about:
$('form.register .submit').click(validateRegister);
function submitStart() {
var $this = $(this);
$this.parent().addClass('processing');
var $processing = $('#processing');
$processing.show();
var $endNote = $this.parent().find('#endNote')
$endNote.slideDown();
}
function validateRegister(){
submitStart();
}
See, when the contents of submitStart() are places into the validateRegister(), they code executes. However, when calling the function as it shows in this code, it fails to work. I've considered scope (at least to my knowledge) to no avail.
Any help is extremely appreciated, thank you!
You're losing your expected this value, so the submitStart is likely getting called, but doesn't work properly.
Do this:
function validateRegister(){
submitStart.call( this );
}
Here you're calling the submitStart method via the .call() method, which is available on function instances.
The .call() method lets you manually set the value of this in the function you're calling.
So because you've assigned validateRegister as the handler, jQuery makes sure the value of this is your element. But since validateRegister is calling another function, it carries the responsibility of making sure that function has the proper this value.
Just keep in mind that when you call any function like this:
someFunction();
...the value of this in that function will be window, unless you manually set it to something else.
var $this = $(this); is returning the window.
this will no longer be referencing the clicked element but will represent window instead. You can change submitStart so that it accepts a parameter and pass this to it.
I think you may have an issue with this not being what you think it is.
Try this:
submitStart.call(this)
The problem here is this. When you use validateRegister as an event hander, jQuery automatically makes sure that this refers to the DOM element that dispatched the event. But when you call your separate function, the scope isn't being set correctly, so this probably refers to the window object (that's the default when you refer to this in the global scope). To fix it, the easiest way would be to pass the element along as an argument:
function submitStart(element) {
var $this = $(element);
$this.parent().addClass('processing');
var $processing = $('#processing');
$processing.show();
var $endNote = $this.parent().find('#endNote')
$endNote.slideDown();
}
function validateRegister(){
// "this" is the DOM element
submitStart(this);
}
As #Andrew noted, you can also set the value of this in submitStart by using the .apply() method of the submitStart function.