Man Im trying to understand callback functions. Ive been over many articles and posts here on SO. The explanations seem circular and I think Im actually getting farther from understanding lol. Ive used them apparently in javascript events, but its more a 'memorize these lines' than 'this is whats going on and why' sort of understanding.
So heres my understanding.
Say you have 2 objects, function p() and function k(). You pass function k to p(). p() can then access k's inner variables.
function p(x){
alert(x.n);//5
}
function k(){
this.n = 5;
}
p(k);
Embarrassing how long its taken me to get just this.
Maybe an example will help?
// First, lets declare the function we're going to call
calledFunction = function (callback, arg) {
callback(arg);
};
// Second, lets declare the callback function
callbackFunction = function (arg) {
alert(arg);
};
// Next, lets do a function call!
calledFunction(callbackFunction, "HAI");
So, calledFunction()'s callback argument is callbackFunction but, if you notice, we aren't calling the function yet, we're passing a variable the contains the function, and its arg function is just something to alert(). When calledFunction() is executed it takes whatever was passed as the callback argument and calls it with arg as its first, and only, argument.
Helped?
Edit: This still works if you use function foo() {}-style declarations. (just in case; I don't know how fluent you are with JavaScript)
You are doing it wrong. this.n = 5; in k() does not set its "inner variable", and x.n access the function object's x property, instead of its inner variable.
Try this:
function p(x) { alert(new x().n); }
Variable binding is an important programming concept.
I think this article helps. http://www.hunlock.com/blogs/Functional_Javascript
Related
Can someone please explain why we can simply pass a method name to a higher order function and everything works just fine. I know in something like Java I have to call the method words on each element individually. I was told that in Javascript if method signature matches we can simply pass in the name of the function with () and it will work. It is great but I want to know whats going on in the background. Why are we able to do this in javascript ?
function words(str) {
return str.split(" ");
}
var sentences = function(newArr){
return newArr.map(words);
}
In many languages you can pass a reference to a function as an argument to a function. That then allows the host function to use that argument and call that function when appropriate. That's all that is going on in Javascript. When you pass the name of a function without the () after it, you're just passing a reference to the function. That enables the host function to use that function as an argument and call it some time later.
In your specific example, .map() expects you to pass in a function that it will call once for each item in an array. So, you pass the name of a function that will then get called multiple times, once for each item in the array. That function you pass has a bit of a contract that it has to meet. It will be passed three arguments (value, index, array) and it must return a value that will be used to construct a new array.
In Javascript, since there is no argument type checking by the language, it is the developer's responsibility to make sure the arguments of the function you are passing match what the caller of that function will actually pass to it and you have to consult documentation of the calling code itself to know what arguments will be passed to it. You can name the arguments anything you want (that is entirely internal to your function implementation), but the order and the quantity of the arguments is determined by the caller and you must declare your function to match what the caller will provide.
Once thing that confused many in Javascript.
If you pass just a function name, you are passing a reference to the function (something that the host function can call at some later time).
array.map(myFn) // passes a function reference
Or, use an inline function (same outcome):
array.map(function(value, index, arr) {
// code goes here
})
If you put parens at the end of the function name, then the function is executed immediately and the return value of that function execution is what is passed:
array.push(myFn()); // pushes the result of calling myFn()
You are calling the words function repeatedly. You're calling it for each iteration of the map function.
The map function takes a callback which it runs for every iteration. That callback is usually in the form of
function (elementOfNewArr, indexOfNewArr, newArr) { }
Because functions are objects, you can store them on a variable and use that new variable name to call that function, instead of its original one. That's mostly the use of functions as objects. You can toss them around.
let foo = function () { return 'jasper!'; }
let boo = foo;
let ron = boo; // ron() will now return 'jasper!'
So, what you've done is plop in your callback function, though it was defined elsewhere. Since callback functions, like all functions are objects, you can declare that callback function, "saving" it to whatever variable you want and use it in anywhere that you can use it normally.
This is super useful if you have to use the same function in more than one place.
What I believe you are misunderstanding is that functions themselves can be treated the same as other variables in javascript. Consider this example:
var newArr = [1,2,3,4];
newArr.map(function(item){
return item * item;
});
In the above example, a function is passed as an argument to the map() function. Notice that it is described anonymously (no function name given). You can accomplish the exact same thing like this:
var newArr = [1,2,3,4];
function squared(item){
return item * item;
}
newArr.map(squared);
These two examples achieve the same thing, except in the second example, rather than writing the function in place, we define it earlier in the code. If it helps, you can even create the function in the same way as you would any other regular variable:
var squared = function(item){
return item * item;
};
You can pass this function around the same way. If you want to know the difference between defining functions in these ways try var functionName = function() {} vs function functionName() {}
I'm using a cordova sqlite plugin. My question does not require you to have an understanding of the API. I'm not having any issues. I'm just a little uncertain about my understanding of the code below and how it works. I'm trying to have a much better understanding of the code I write.
So first, this variable "db" is defined as being a function (object) named "openDatabase" with parameters that the plugin understands and it's being called.
"db" which is actually a function (object) called "openDatabase" has a method called "transaction".
Am I doing alright so far?
Here's where I get a little confused: The db variable which is now equivalent to the openDatabase function has a method called transaction and it has a self invoking function as a parameter and the self invoking function has this variable "tx" as a parameter? Where does "tx" come from? Is it an object the "openDatabase" function returns after it's called? or is it not returned from "openDatabase" and it's just simply an object from the plugin? Is it always safe to assume variables as parameters that I haven't defined anywhere, that work, have been defined in the plugin, library or API I'm using? My last question is, why use a self invoking function as a parameter instead of a variable defined as that self invoking function? Any benefit? Thank you.
var db = openDatabase("DBTest", "1.0", "Sample Description", 200000);
db.transaction(function(tx) {
tx.executeSql("SELECT * FROM Table1Test", [], function(tx, result) {
for (var i = 0, item = null; i < result.rows.length; i++) {
item = result.rows.item(i);
document.getElementById('results').innerHTML +=
'<li><span> + item['text'] + '</span></li>';
}
});
Here's what's happening in that code, then I get to your specific questions:
db is being set to the return value from openDatabase. Then, the code calls db.transaction, passing in a callback function. The callback is called by db.transaction, which supplies the tx value, and in the callback we call tx.executeSql, passing in a second callback function. executeSql calls that second callback with the results, which code inside the second callback loops through.
Your questions:
So first, this variable "db" is defined as being a function (object) named "openDatabase" with parameters that the plugin understands and it's being called.
No. openDatabase is being called, and db is being set to its return value. That return value appears to be an object, but not a function (although it could be, there's no evidence that it is and it probably isn't).
"db" which is actually a function (object) called "openDatabase" has a method called "transaction".
Yes, except that db is probably not a function (although it could be), it's just an object.
The db variable which is now equivalent to the openDatabase function...
It isn't.
...has a method called transaction and it has a self invoking function as a parameter...
It's not self-invoking.
...and the self invoking function has this variable "tx" as a parameter? Where does "tx" come from?
Because the callback function isn't self-invoking, the tx argument's value comes from whoever calls the callback. The code in the transaction method will call the anonymous callback in that code. When it does, it will supply the value of the tx argument to that function. Similarly, the callback passed into executeSql will get called with values for tx and result.
Is it always safe to assume variables as parameters that I haven't defined anywhere...
Probably not. Instead, continue your study of JavaScript (you're clearly in the process of learning, which is great). You'll learn the syntax and be able to tell what's an argument, what's a variable, etc. Here's some info on that as comments:
var db = openDatabase("DBTest", "1.0", "Sample Description", 200000);
// ^^---- variable
db.transaction(function(tx) {
// Argument ------------^^
tx.executeSql("SELECT * FROM Table1Test", [], function(tx, result) {
// Arguments ----------------------------------------------^^--^^^^^^
for (var i = 0, item = null; i < result.rows.length; i++) {
// Variables ----^------^^^^
item = result.rows.item(i);
document.getElementById('results').innerHTML +=
'<li><span>' +
item['text'] + '</span></li>';
}
});
});
Part of the confusion here seems to be with callbacks, so let's look at a much simpler version of callbacks, and one where we can see both sides of it.
Suppose something provides us a function, countUp, which we can give a start and end value to, and which will then call us with each value between:
countUp(0, 5, function(value) {
console.log(value);
});
And suppose when we use that, we get:
0
1
2
3
4
In our code above, we create but never call the callback we're passing to countUp. It's countUp's code that calls the callback. Here's what countUp might look like:
function countUp(start, end, callback) {
// ^^^^^^^^---- the callback argument
var i;
for (i = start; i < end; ++i) {
// vvvvvvvv------- calls our callback
callback(i);
// ^----- passing in this, which we get as `value`
}
}
Live Example:
function countUp(start, end, callback) {
var i;
for (i = start; i < end; ++i) {
callback(i);
}
}
countUp(0, 5, function(value) {
snippet.log(value);
});
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
So first, this variable "db" is defined as being a function (object) named "openDatabase" with parameters that the plugin understands and it's being called.
No. The function stored in openDatabase is called and it's return value is assigned to db.
"db" which is actually a function (object) called "openDatabase" has a method called "transaction".
The value assigned to db is an object.
It might be a function, but there's no evidence in the code to suggest that it is.
It does have a method called transaction.
it has a self invoking function as a parameter
No, it doesn't.
foo( function () { } );
bar( function () { }() );
foo has a function as an argument.
bar has the return value of an immediately invoked function expression as an argument.
You can't have an IIFE as an argument itself because the IIFE resolves before the value is passed to the function.
transaction has a function passed as an argument.
Where does "tx" come from?
The transaction function (assuming the anonymous function doesn't get passed around some more first) will call the anonymous function. It will pass it arguments when it does.
Is it always safe to assume variables as parameters that I haven't defined anywhere, that work, have been defined in the plugin, library or API I'm using?
Yes
My last question is, why use a self invoking function as a parameter instead of a variable defined as that self invoking function?
If you mean Why use a function expression instead of a function stored in a variable? then it just saves the step of creating the variable and it keeps all the code together.
openDatabase is a funtion which returns an object that gets assigned to the db variable. This object has a method, transaction, which takes a function as an argument. When you call the transaction method, it sets up a transaction and then calls the function you pass it, with the newly-created transaction as its argument (the tx in your example). The function can now use the transaction to query the database. When it returns, the transaction method will do any necessary cleanup, and then return to the toplevel code.
This is too long for a comment yet doesn't directly answer the question. However, understanding this concept will hopefully allow you to answer all your questions yourself. Therefore I'm posting this as an answer.
Main concept: Functions are just objects just like numbers, strings etc.
You've probably seen code that looks like this:
var x = function (a) {...}
That is not a special syntax to declare functions. It is merely possible because functions are first class in javascript. First-class refers to things in the programming language that can be treated as data. In most languages numbers and arrays are first-class "things" (I'll avoid using the word "object" for now because it may have specific meanings in some languages, javascript included). In a lot of languages strings are also first-class things. In a few languages even functions are first class things.
Javascript is one language where functions are first-class: they can be treated as data
function x () {};
// you can assign them to variables:
var y = x;
y(); // call the function
// you can put them in arrays:
var a = [x,y];
a[0](); // call the function
// you can pass them as argument:
funtion b (foo) {
foo(); // call the function passed to b()
}
b(x); // this will cause b() to call x()
So when you see this:
db.transaction(function(tx) {/*...*/});
it's basically doing this:
function my_function (tx) {/*...*/}
db.transaction(my_function);
Therefore, you can sort of guess that db.transaction() looks something like this:
db.transaction = function (another_function) {
/* complicated processing ... */
another_function(result); // pass result variable to the function
// the user gave us.
}
So when you call:
db.transaction(function(tx) {/*...*/});
the function db.transaction() will call your function and pass it an argument (which you have defined as tx).
Think of tx as sort of the return value from db.transaction().
Is it possible to assign a whole line of code to a function parameter? Take this example:
function testFunc(parameter1){
parameter1;
}
testFunc($(".someClass").text("someText"));
When the function is used with that parameter, can the parameter1 be replaced by the line of code?
I'm new with JavaScript and jQuery, so I'm just curious if this is possible. I did not see any questions like this asked before. But if it was asked, a link to the question would be appreciated. Thanks
Sounds like you are inventing the callback :)
Pass an actual function and call it with ();
function testFunc(callback){
callback();
}
testFunc(function(){$(".someClass").text("someText");});
Yes it can be done , as jQuery will eveluate it and return a object.
The key insight here is that a function can be treated like any other variable.
For example:
var i = 1;
var f = function() { console.log('hello!'); };
Here f is a value, just like i is, but you can invoke it just like any other function:
f(); // prints 'hello!' in the console
Because it is a value, you can pass it to another function:
function g(h) { h(); }
g(f); // prints 'hello!' in the console
Take the time to ensure you understand the above code. I've deliberately used vague names so you can learn the mechanics. Let me know if you have any questions.
Arguments aren't assigned to functions, they are passed/sent/[insert other synonym here].
Anything that is an expression (any code which evaluates to some value) can be passed around.
In your exemple $(".someClass").text("someText") is an expression which evaluates to a jQuery object, so you can use this unit of code as a function's argument without any doubt.
However, if you want to pass around some code which has to be executed as part of an existing function's process, you must use a function expression which encapsulates that behavior.
E.g.
function executor(task) {
task();
}
executor(function () {
//code to be executed by the executor
});
Yes you can pass function callback like regular primitive variable
In your case you should check param type before execution
function testFunc(parameter1){
if(typeof parameter1==="undefined"){
//arguments[0] will fall here
console.log("No arguments case. parameter1 not defined")
}
else //function check
if(typeof parameter1==="function"){
//you can parameter function here.
return parameter1();
}
else{
//regular case value or object, other than function types fall here
console.log("not a function, received param type: "+ typeof(parameter1));
return parameter1;
}
}
$(function (){
//let us say you have below vars
var primitiveVar="test",
fun = function(){console.log("function fun call")};
//no args here
testFunc();
//sending primitiveVar
testFunc(primitiveVar);
//below is your call with jQuery Obj
testFunc($(".someClass").text("someText"));
});
I am stumbling upon a problem that I have seen before, but that I couldn't solve before. I will likely stumble upon it again in the future, so please, someone explain it to me what is going on?
In the partial snippet of javascript below, I have a function that populates a screen, including an order combobox (twitter bootstrap). When I click on one of the order items in that combobox, it should invoke the function clsModCampaigns.blnCompaniesListReload().
For a reason that I don't understand, once inside the '$.each' iterator, the global object reference 'objModCampaigns' is lost? I get a successful alert '1', but not an alert '2'.
Within the $.each, I would like to use 'objModCampaigns.arrOrderBy' instead of 'this.arrOrderBy', but the $.each iterator only seems to work this way. Why is it working this way??
What is going on with 'this', or with variables/objects assigned in the root of the class with 'this'?
Is $.each just special??
function clsModCampaigns(objSetSystem, objSetModuleBase)
{
objModCampaigns = this;
arrOrderBy = {
intID: 'ID',
strName: 'Name'};
[...]
this.blnScreenCampaignInitialize = function (fncSuccess,fncError, intID) {
$.each(this.arrOrderBy, function (strFieldName, strFieldDescription) {
if(strFieldName != 'datDeleted' || objSystem.blnHasPerm("CAMPAIGNS_DELETED")) {
strOrderByID = "ulCampaignsCompaniesListOrderBy" + strFieldName;
$("#ulCampaignsCompaniesListOrderBy").append('<li>'+strFieldDescription+'</li>');
$("#"+strOrderByID).unbind("click").bind("click", function() {
alert("1");
objModCampaigns.arrCurrentShownCompanies.strOrderBy = strFieldName;
objModCampaigns.blnCompaniesListReload();
alert("2");
});
}
});
return true;
};
}
The code you have is
$.each(this.arrOrderBy, ...);
You want
$.each(arrOrderBy, ...);
The reason for it is the this context on that line is different because it is inside a new function this.blnScreenCampaignInitialize.
This is just a part of how JavaScript works
var message = "hello";
function welcome() {
console.log(message);
}
welcome(); // "hello"
P.S. use var
If you don't use var, you'll be attaching all of your vars to the global object.
function hello() {
foo = "bar";
console.log(foo);
};
hello(); // "bar"
console.log(foo); // "bar"
// Holy smokes! `foo` has escaped our `hello` function!
Compare that to
function hello() {
var foo = "bar";
console.log(foo);
}
hello(); // "bar"
console.log(foo); // ReferenceError: foo is not defined
// much better
Now let's see a terrible example
function a() {
b = 5;
return b;
}
function b() {
return "function";
}
console.log(a()); // 5
console.log(b()); // TypeError: number is not a function
This is happening because we didn't use var properly. We first define b as a function but after running a(), b is now set to 5. The second log statement is the equivalent of trying to run 5() because b is no longer a function.
P.P.S. it's pretty unconventional to prefix your vars with str, int, fnc, obj, or cls in JavaScript.
I understand you're a "VB guy" according to your comments, but that's no excuse for bringing your own conventions to the language. I see in your profile that you're fluent in Dutch, English, German, and French. I would recommend you treat learning programming languages much the same as spoken languages: each of them have their own explicit set of rules and conventions.
Here's a heap of free JavaScript books for you. I hope they can help you learn some more basics.
P.P.P.S. Overall, your function is really big as it is, and I can see you already truncated some of the code with your [...]. The whole thing could probably benefit from some better composition.
If you paste all of your code, maybe someone could help you better.
What is going on inside the $.each() ?
Regarding you question title, I'm trying to answer:
// each function in source
function (obj, callback, args) {
//...
}
Check the source of complete $.each function by yourself, you can see any function's source code just by typing the function name in the appropriate text box (the second on top).
Here in each function, the array/object passed in to the each function (the first argument) is being run through a loop and each value is being passed in to the callback (second argument) and that call back is getting executed like:
callback.apply(obj[i], args);
So, the passed callback in the each function is being executed each time the loop occurs ad the current value in the loop is passed as the argument of callback function along with the third argument args.
If your function function clsModCampaigns(){ //... } is a normal function then this inside this function points to global window object. so just use:
$.each(arrOrderBy, ...);
instead of
$.each(this.arrOrderBy, ...);
Because, arrOrderBy is within the direct scope so arrOrderBy is accessible directrly. For example:
function someThing()
{
var x = 'y'; //<-- this scope (everything inside someThing) is
// global for somethingElse inner function
function someThingElse)(x) //<-- possible to use directly
{
}
}
The keyword this behaves differently depending on the context. Check about this on MDN.
I have am trying to understand the Javascript/jQuery behind ColorBox. Some forms of syntax are a bit hard to search on Google as they are a bit lengthy to describe. I am having trouble understanding the following line:
publicMethod = $.fn[colorbox] = $[colorbox] = function (options, callback) {
So I assume a new function called publicMethod is being created, but how do we but I don't really understand anything beyond the first equals symbol ("=").
A normal function declaration would look like this:
function publicMethod(options, callback) {
So if anybody could help me understanding the syntax I would greatly appreciate it.
In:
$.fn[colorbox]
$ is an unhelpfully non-descriptive variable name. It contains an object.
$.fn access the fn property of that object.
fn[colorbox] accesses the property of that object which a name that matches the string stored in colorbox
But the right hand side of and = is defined first, So before it assigns that value to publicMethod it assigns the value of $[colorbox] to $.fn[colorbox].
… and before it does that it assigns (to there) a function.
function () {} defines an anonymous function and passes it left (so it gets stored in whatever is on the other side of =)
In JavaScript, functions are on the same level as other objects - you can assign them to variables, and pass them as parameters.
Normally, you would declare a function in this way:
function SomeFunc(arg1, arg2) { /* etc etc */ }
An equivalient way would to be:
var SomeFunc = function(arg1, arg2) { /* etc, etc */ }
...because, as above, functions themselves are values that may be assigned or passed.
Many libraries will accept functions as arguments to their own functions, running the passed function at a time which suits them (or passing them on elsewhere, a la any other variable). Often this is for callbacks. When passing functions as arguments, there isn't really a need to give them a name of their own, thus the following does the job:
SomeLibrary.doSomethingThenCallback(function(arg1, arg2) {
// the doSomethingThenCallback function will decide when, if ever,
// to run this, or pass it on somewhere else, or whatever else would
// be done with any other argument value.
});
This function publicMethod(options, callback) {} is nearly but not completely the same as var publicMethod = function(){options, callback}. In first case you create function named publicMethod and in the second you create anonymous function and assign it to publicMethod variable. Other to assignations just save this function for the further use as API method.