Javascript anonymous functions with parameters. Where are those parameters defined? - javascript

I had a doubt about replacing some characters in a textbox using jQuery and I landed in this question. The accepted answer suggested something like this:
$("#mySelector").val(function(i, v) { //i, v... where they come from??
return v.replace("#","Custom Text");
});
That works fine but I still have the same doubt. Those parameters, i and v. Where do they come from and how they are filled with data? They are not declared anywhere. How do i and v in this case, has the data that I need?
These answers talk about it, but it seems just an overcomplicated explanation for what should be, an easy thing to explain.
So, the question is simple. How in the world those parameters in the anonymous function, get filled with data. Where do they come from if I didn't declare them anywhere?

They are set when the jQuery library calls the callback. Note that you are passing a function as a parameter into the $.val function. The $.val function passes values to the function that you passed to it.
Here is a simple example of how callbacks work:
function coolFunction(callback) { // accepting callback
// extra processing here
callback(1, 2); // calling the callback
}
coolFunction(function(a, b) { // passing function as callback
console.log('annonymous', a, b);
});

The jQuery function val checks the argument passed into it. When it finds a function, it calls it for every element contained in the selector, where i is the index of the element in selector, and v is the value... ie the element's value.

Related

JQuery 3.3.1 attr with 3 parameters. What it does?

I'm trying to update some old code someone left before, at some point, it made a call to the attr function of an old 3.3.1 JQuery like this:
$("#myiframe").attr("src", url, function () {
$(window).on("unload", function () {
// Some function stuff
});
});
My problem is than I want to know what exactly this does (I already know what attr does when it has 2 parameters, but not 3) before adapt it to a newer version, but when I search about the .attr function in JQuery, all I found is with only two parameters, not 3 like this, I don't know if is properly a callback function (unlikely, because none of the parameters this function accepts is a callback function), or other thing.
The JQuery file is the one served by googleapis, so is not likely it has been specially modified for this.
Please, can someone explain me what it does?
No signature of attr() accepts 3 arguments. The last argument is redundant. Even if it did serve a purpose, putting a window.unload event handler in there would not do anything useful.
Regards your comment under the question:
Why doesn't it launch a fatal error for the number of arguments?
It's because JS is a very permissive language. You can pass as many arguments to a function as you like, JS will ignore any extras and only bind those which you defined in the function definition (up to 2 in this case using attr()). Although note that it's still possible to retrieve all arguments that were used in the function invocation using the arguments keyword

Javascript callback functions differences

I would like to know the difference between 2 implementations of callback functions.
This:
$("#button").on('click', function () {
//do something
});
Versus having the function already defined.
$("#button").on('click', btnFunction);
function btnFunction() {
//do something
}
Are there any implications with one compared to another? Performance-wise is one faster?
The first uses an anonymous function and the second does not. There's no difference in both.
See:
Why do you need to invoke an anonymous function on the same line?
Some folks prefer the second form because it gives a function name when using the debugger and tracing, but there are ways to get the same functionality in the first form.
If you are attaching and removing the event handler based on changing conditions, the second form is much easier to maintain, however.
There's no difference at all, and there's no performance issue with neither one of them. The only difference is that in one of them you're defining the callback function as an anonymous function, this way you cannot reuse it.
The other way, where you define it else where and named it and then pass it as a callback, you're defining a function that you can later reuse in another part of your code.
For example: if you want to do something when the document is ready, and then do se exact same thing when some one press a button you can use something like this:
function getData() {
//do something
}
$(function() {
// Call the function once the DOM is ready
getData();
});
// Call the same function when the button is clicked
$("#refresh_button").on('click', getData);
In most cases the first one will be used, called Anonymous Functions
The second one will be used when the function is not only used inlined here, but also needs to be reused somewhere else.
But anyway it could be a personal preference.
The only real difference you could see is that stack trace (if an exception is thrown for example) will be better, i.e. easier to debug, when using the second one.
Just reuse-ability.
In the second case, you could call btnFunction() somewhere else if need be.

JS / Jquery .load and .length

I'm new to Jquery/javascript with almost all of my experience being in PHP. I am now finding the importance of how things are ordered :)
So I'm trying to load some <div>s into the container #text-container using .load and then count them. My understanding of jquery's load function is that the 2nd argument is a callback function which will only run once all data has been loaded. But it is always reported as 0 even if there are 4-5 divs being placed in the container. Am I missing something?
1.txt
<div>1</div><div>2</div>
Code:
$("#text-container").load("1.txt",alert($("#text-container div").length));
This is just an example but I need to use that number to do a whole bunch of maths in other functions. So if I call those instead of alert and try to run .length in there they all get 0 and my math doesn't work :(
Ideas?
You need an anonymous function for the callback
$("#text-container").load("1.txt", function(data) {
alert( $("#text-container div").length )
});
This is just an example but I need to use that number to do a whole
bunch of maths in other functions.
Note that it's async, so you can't use it until it's actually there, and why would your .txt file contain DIV elements, seems like the wrong file extension to me ?
Answer
$("#text-container").load('1.txt',function(){
alert($("#text-container div").length);
});
Explaination
First let us talk about the callback function passing, the right syntax:
$(selector).load(source,callback);
Suppose you have some function named as gg and we want to use it in place of callback
function gg(){
//some code for task 1
}
now lets use it as callback
(the wrong way)
$(selector).load(source,gg());
Note: when you write the function with parenthesis (), the function is called at the same time, so you just need to pass the identifier
(the right way)
$(selector).load(source,gg);
OR USE ANONYMOUS FUNCTION
$(selector).load(source,function(){
// some code for task 1
});
Note: Instead of defining a function only for callback and if you are not using it again it is preferred to use anonymous function
You are not doing what you think you do. You pass the result of alert() as an argument.
$("#text-container").load("1.txt",alert($("#text-container div").length));
is equivalent to :
var data = alert($("#text-container div").length); // data = 0
$("#text-container").load("1.txt", data);
What you want is to pass a function as an argument :
var callback = function() {
alert($("#text-container div").length);
}
$("#text-container").load("1.txt", callback);
or shorter :
$("#text-container").load("1.txt", function() {
alert($("#text-container div").length);
}

What is the point about callback

I learn now that a callback is function that pass to argument.
but I can do it without so what is the point?
for example
function i()
{
alert("callback");
}
function p(a)
{
for(r=0;r<100;r++)
{document.write(r);}
a();
}
p(i);
or
function i()
{
alert("callback");
}
function p()
{
for(r=0;r<100;r++)
{document.write(r);}
i();}
I searched but could not find an answer
Callbacks are usually used when you want to do something with some data that isn't immediately available.
For example, to process some data from an HTTP response when the response arrives or to perform an action based on where a mouse click occurred when the mouse button is clicked.
So to take you example, yes if you want to call i() in function p() you can just go ahead and do that. But what if you want a function just like p() accept that it calls j() at the end instead of i()? Well, that's easy, you pass a function as a parameter for p() to call at the end instead of hardcoding it.
It's about flexibility. There's no need to do it for the sake of doing it, but there are many cases where it's useful.
So let me try and come up with a simple example, let's say we have a function called sum() that adds up all the elements of an array. Now let's say somewhere in our program we want to sum not all the elements, but some of the elements, maybe only the elements over a certain value, or every other element. If we set up sum so that it could take, in addition to the array to work on, a function parameter that will call filter (which if left null, we'll just sum all the elements by default), we could make our sum() function much more useful and avoid writing a whole bunch of different sum functions.
Also, as Quentin already answered, it's especially useful for asychronous functions.

Anonymous function references in Javascript

I'm currently in the process of building out a VERY simple Observer class for a project I'm working on. I have successfully implemented the subscribe, unsubscribe, and notify methods. Everything works exactly as expected when using "regular" functions (i.e: var f = function()).
However, when I pass an anonymous function to the subscribe method and then try to unsubscribe passing the "same" anonymous function it (as expected) doesn't remove the function from my array (they are different, after all).
Here's my subscribe and unsubscribe methods:
this._subscribers = {};
subscribe: function(type, callback) {
if ( isUndefined(this._subscribers[type]) ) {
this._subscribers[type] = [];
}
this._subscribers[type].push(callback);
},
unsubscribe: function(type, callback) {
if ( this._subscribers[type] instanceof Array ) {
var index = this._subscribers[type].indexOf(callback);
if ( index >= 0 ) {
this._subscribers[type].splice(index, 1);
}
}
},
And here's the code I'm testing with:
var o = new gaf.events.Observable();
o.subscribe('testEvent', function(event) { alert('Got It!'); });
o.notify('testEvent');
// Correct alerts 'Got It!'
o.unsubscribe('testEvent', function(event) { alert('Got It!'); });
o.notify('testEvent')
// Incorrectly alerts 'Got It!'
I know I could using an object (i.e.: _subscribers[event] = {}) and then when something subscribes I could add a new property equal to the callback and the value equal to the callback. This will cause Javascript to convert the callback to the string. I could then look it up (provided the methods passed in sub/unsub are exactly the same) using that string.
However, this is a mobile project and I'm very leery about storing strings that could be hundreds of characters long as properties as we could end up with a lot of subscribers.
Are there any other ways of doing this? Are there any SMALL (tiny, even) hashing libraries I can use to maybe hash the string value of the function and use that as the property? Would it be better to store the string value of the callback (so I can compare against it) in the array (rather then the actual callback) and use eval() on it?
EDIT
First, thanks all for the replies!
Per all the questions about "Why even pass anonymous" functions -
There really is no reason one COULDN'T use named functions. In fact, I agree with everyone that named functions are going to be the better solution. I'm simply gathering information and looking for a solution so that I can build out an implementation that handles the most scenarios as best as possible.
The other reason for this is what happens if a user (co-worker) of this Observable class passes it an anonymous function and then unsubscribes. That function won't actually be unsubscribed and therefore won't be cleaned up. I have a thing against orphaned data :)
Maybe another question I should as is, is it possible to test if the callback is anonymous or not? I'm going to assume no but doesn't hurt to ask.
There is nothing wrong with storing the entire string; premature optimization is evil.
However, this sounds like an incredibly bad idea.
If someone changes the function, but forgets to change the unsubscribed copy, the code will be subtly broken with no warning whatsoever.
Instead, you can require the user to store the anonymous function in a variable if they want to unsubscribe from it.
Alternatively, you can pass an optional name with each subscriber, then unsubscribe by that name.
the clients that use the Observer should store the reference to the function.
var obsCallback = function() {
}
o.subscribe('test', obsCallback);
....
o.unsubscribe('test', obsCallback);
in other words, keep a reference to the function around...
Perhaps a better solution is to modify the code using your library
var f = function() { alert('Got It!'); };
o.subscribe('testEvent', f);
o.notify('testEvent');
o.unsubscribe('testEvent', f);
o.notify('testEvent');
You could even return the function from the subscribe method
var f = o.subscribe('testEvent', function() { alert('Got It!'); });
// ...
then if you want to store a hash or some other identifier for subscribed functions, it is opaque to the calling code meaning that you just use the returned value to unsubscribe and the library hides the implementation detail.
What is the reason for passing in anonymous functions rather than named ones, or keeping references that you can use for unsubscribing later?
Alternatively you could allow for an optional 'id' argument but this would require unnecessarily complex bookkeeping to avoid duplicates.

Categories