I am teaching myself javascript and one of the exercises I have tried makes no sense to me.
In the code below 'position' is a parameter that must be defined. However, when I pass the function, displayLocation as an argument to navigator.geolocation.getCurrentPosition, the code executes flawlessly, despite no argument being passed. When I try coords.longitude in the console without the position argument, it does not work.
How does the code work without a defined argument?
function displayLocation(position)
{
var latitude = latitude.coords.latitude;
var longitude = position.coords.longitude;
var div = document.getElementById("location");
div.innerHTML = latitude + " " + longitude;
}
navigator.geolocation.getCurrentPosition(displayLocation);
When I try coords.longitude in the console without the position
argument, it does not work...
How does the code work without a defined argument?
Arguments of function in JavaScript are optional.
If you don't pass it, it has as value : undefined.
So, yes the function accepts an invocation with a missing argument position but position.coords would not be usable.
navigator.geolocation.getCurrentPosition(displayLocation); calls your function with an instance of Position, as documented here.
Please take into account that displayLocation is not called immediately but delayed. This is why you pass it as a callback function.
What you are doing when you do
navigator.geolocation.getCurrentPosition(displayLocation);
is that you are calling navigator.geolocation.getCurrentPosition, and giving it a handle to your function displayLocation. You cannot say that displayLocation is getting called without an argument. That depends on what getCurrentPosition does with that handle. What it does is that it creates a position object, and then calls the function you gave it, with that object as a parameter. More succinctly, getCurrentPosition calls displayLocation with a position object, it created, as a parameter.
Let's take a look at Geolocation.getCurrentPosition. The required parameter success is a callback function.
Inner workings of the Geolocation.getCurrentPosition(displayLocation) will look roughly like the following:
function getCurrentPosition(callback, ...){
var positionGCP;
...
...
positionGCP = *someposition*;
// done getting current position
callback(positionGCP)
//passed in function gets called back!
}
and the last line (callback(positionGCP)) really runs displayLocation(positionGCP) since callback == displayLocation.
Does that make sense?
The following link may help:
Passing parameters to a callback function
Related
I'm trying to understand the below code which prevents bugs caused by a function silently passing to a call back function more arguments that aren't wanted in the parameters of the callback function:
["1","2","3"].map(parseInt)
returns [1, NaN, NaN] because the index gets passed as a second parameter to parseInt which accepts it as the radix, so the array values are invalid. To solve it, the author of this blog post suggests a js extension:
Function.prototype.only = function(numberOfArgs) {
var self = this; //the original function
return function() {
return self.apply(this,[].slice.call(arguments,0,numberOfArgs))
}
};
Which would be called like so:
["1","2","3"].map(parseInt.only(1))
I'm struggling to understand why "this" is passed as a function parameter while self is returned as a reference to this. They both point to parseInt correct? Is there a difference in binding times of parameters vs return values?
They both point to parseInt correct?
No.
The value of this depends on how a function is called.
The function passed to map gets called by the internals of map.
Look at the documentation for map.
If a thisArg parameter is provided to map, it will be used as callback's this value. Otherwise, the value undefined will be used as its this value.
So if the returned anonymous function used this instead of self it would be calling undefined.apply not parseInt.apply.
I'm struggling to understand why "this" is passed as a function parameter while self is passed as a reference to this. They both point to parseInt correct?
No. self will refer to parseInt. this will be whatever this the function was called with, which could be anything. In your example:
["1","2","3"].map(parseInt.only(1))
...this will either be a reference to the global object (in loose mode) or undefined (in strict mode), because map will use undefined when calling the callback (which is turned into a reference to the global object in loose mode).
There are several ways this might be something else though:
If a second argument were passed to map:
["1","2","3"].map(parseInt.only(1), {})
// Second argument -----------------^^
...it would use that value rather than undefined when calling the callback.
If Function#bind were used on the function only returns:
["1","2","3"].map(parseInt.only(1).bind({}))
// Bind ---------------------------^
...then this would be that value.
If the function only returns were called with call or apply (which is what map does, so this is kind of a repetition of #1 :-) ), the value supplied for this would be used.
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 was checking out an example of javascript code from w3schools:
http://www.w3schools.com/html/tryit.asp?filename=tryhtml5_geolocation
If function showPosition by definition has a parameter called position:
function showPosition(position) {... }
why is it possible to call it with no parameters:
navigator.geolocation.getCurrentPosition(showPosition);
Example is functional, just trying to understand it
In fact am surprised showPosition has a param at all. Would you change that?
That's not calling the function, it's passing the function as an argument to another function. getCurrentPosition uses the argument as a callback, and it will later call the function with the appropriate argument.
A function call always has parentheses after the function name, e.g. showPosition(something).
There is arguments array-like object in JS which allows to skip actual parameters at all and use arguments[0] for position in your case.
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().
My html contains two forms overlapping each other, one used as add form and one as edit form. I use jQuery to show and hide them with the following code:
var editForm = $("#edit-form");
var addForm = $("#add-form");
var showEditForm = function() {
editForm.fadeIn(function() {
addForm.fadeOut();
});
};
var showAddForm = function() {
editForm.fadeOut(function() {
addForm.fadeIn();
});
};
I wanted to make the code more compact so I set the fadeOut() call directly on the fadeOut() callback by doing like this:
var showEditForm = function() {
editForm.fadeIn(addForm.fadeOut);
};
var showAddForm = function() {
editForm.fadeOut(addForm.fadeIn);
};
But this productes the following error Uncaught TypeError: Failed to execute 'animate' on 'Element': Valid arities are: [1], but 4 arguments provided. but why doesn't that work?
That's because calling a function as a property of an object is a special syntax, that calls the function with the object as context.
When you call a function like this:
obj.func();
then this will be a reference to obj inside the function.
If you get the reference to the function, and then call it:
var f = obj.func;
f();
then this will be a reference to the global context, i.e. the window object.
By using editForm.fadeIn(addForm.fadeOut); you get the reference to addForm.fadeOut and send to the fadeIn method. It's no longer associated with the object, so it will be called with the global context instead of the object as context.
You can use the proxy method to associate the function with the object, so that it will be called with the correct context:
var showEditForm = function() {
editForm.fadeIn($.proxy(addForm.fadeOut, addForm));
};
var showAddForm = function() {
editForm.fadeOut($.proxy(addForm.fadeIn, addForm));
};
I suspect the problem is that addForm.fadeOut is being called with a bad combination of arguments, when its passed to the fadeIn function (and vice versa).
The classic example of this pitfall seems to be:
["0", "1", "2", "3"].map(function(i) {return parseInt(i);})
This, works as expected and gives [1,2,3,4] as a result. You might expect that you could shorten this, much as you did above, and write
["0", "1", "2", "3"].map(parseInt);
Unfortunately; this evaluates to [0, NaN, NaN, NaN]. The problem, is that .map calls any function provided it with three arguments: the value, the index, and the array itself, and parseInt takes up to two arguments: the value, but also the radix/base to parse in. (e.g. radix 2 to parse a string as binary) So what actually happens is essentially:
[
parseInt("0", 0), //0, radix is ignored
parseInt("1", 1), //NaN, what is base 1?
parseInt("2", 2), //NaN, 2 isn't valid binary
parseInt("3", 3) //NaN, 3 isn't valid ternary/base-3
]
I suspect, based on the error message, that the same thing is going on here. The "arity" of a function is the number of arguments passed to it, so the error message here says that 4 arguments were provided, when only one was expected.
In general with functions that take optional arguments, you need to be careful before passing them to other functions directly, or else you can't control what arguments it will be called with.
Fiddle: http://jsfiddle.net/jmj8tLfm/
addForm.fadeIn and addForm.fadeOut are being called without specifying the this context that would normally be passed when you call addForm.fadeIn(). Try .bind()-ing the this variable appropriately as follows:
var showEditForm = function() {
editForm.fadeIn(addForm.fadeOut.bind(addForm));
};
var showAddForm = function() {
editForm.fadeOut(addForm.fadeIn.bind(addForm));
};
If you are writing in vanilla js. The reason as to why you need too pass the callback function in an anonymous function has to do with function invocation.
Take a look at this example:
const firstFunc = (callback) => {
setTimeout(function() {
console.log('yes');
console.log(callback())
}, 3000);
}
const secondFunc = () => console.log('great');
firstFunc(function(){
secondFunc();
});
// prints 'yes' 'great' after 3 seconds
> yes
great
When invoking the function, if you pass the callback argument without the parenthesis i.e firstFunc(secondFunc); the callback function will invoke after the first function has finished (just like above) provided inside the first function where the callback gets called is invoking that function. i.e callback(), the () is the important part.
Try omitting the parenthesis inside the first function like this, callback and pass the second function as a callback without the parenthesis firstFunction(secondFunction) notice how you are passing the callback function but it is never being invoked. Your console.log() should look like this.
> yes
() => console.log('great')
So why does this matter...
If you pass the function invocation as firstFunc(secondFunc()) using the setup from the first code snippet. You will notice that the second function prints first then 3 seconds later the first function is invoked.
> great
yes
Given that Javascript is event driven, the invocation of the second function can be found const secondFunc = () => console.log('great'); and it will immediately invoke that function not waiting for the response from the first function. That is what the () did when you invoked secondFunc() inside firstFunc.
By passing an anonymous function that function is never being invoked until it reaches the callback() invocation part. Again using the setup from the first code snippet, try.
firstFunc(function(){
secondFunc();
});
firstFunc(function(){
secondFunc();
}())
See how the second call invokes the secondFunc right away. What is happening is the anonymous function is a wrapper to not invoke your function right away.
Why is this useful?
If secondFunc takes a callback that callback function would not be invoked until the second function has finished executing. You would need to call that callback function inside your second function.
firstFunc(function(){
secondFunc(function(){
thirdFunc();
});
});