How a function got passed to another function? - javascript

I came across a weird code which I didn't understood. It would be great if I get explanation.
function forEach(array, action) {
for (var i = 0; i < array.length; i++) {
action(array[i]);
}
}
var numbers = [1, 2, 3, 4, 5], sum = 0;
forEach(numbers, function (number) {
sum += number;
});
console.log(sum);
How the function got passed as parameter ? and how the inner function is getting that number.

In JavaScript, functions are what's called first class citizens (that's not necessarily true for other languages), that means that functions can be treated as data, you can pass functions as arguments, return functions from other functions, and create functions and assign them to variables.
Here's a very simple example:
function callWithoutParams(fn) {
return fn(); // fn is the passed function.
}
let rand = callWithoutParams(Math.random); // Passing Math.random as a function.
callWithoutParams(() => console.log(42)); // Passing anonymous function
Array.prototype.forEach() accepts a function as an argument, and runs it on each element in the array. So a simpler example is:
[1,2,3,4,5].forEach((element) => console.log(element)); // outputs 1-5 in order.

In javascript, everything is an object, including function.
For simplicity, check this example:
var func = function(number){
console.log(number);
}
var arr = [1,2,3,4,5];
function foreach(data, callback){
for(var i = 0; i<data.length; i++){
callback(data[i]);
}
}
foreach(arr, func);
In JS, you can assign function to a variable. This is called as Function Expression. So it acts as a normal variable, just that its type is object.
This allows us to pass function as a parameter.
Now your second question, how the inner function is getting that number.
in your code, action(array[i]); is passing value as a parameter, so
function (number) {
sum += number;
}
here number is array[i].

Related

How to return a function that needs 2 parameters with 1

I believe I have solved this problem but having an issue only passing 1 parameter to my final function to return result. Here is the question
For instance, consider the function getDouble. When run twice on value 3, yields 12 as shown below.
getDouble(3) => 6
getDouble(6) => 12
Let us name the new function createIterator and we should be able to obtain the same result using createIterator as shown below:
var doubleIterator = createIterator(getDouble, 2); // This means, it runs *getDouble* twice
doubleIterator(3) => 12
For the sake of simplicity, all function inputs to createIterator would be functions returning a small number and number of iterations would always be integers.
Here is my answer:
function getDouble(num){
newNum = num * 2
return newNum
}
var createIterator = function (func, n) {
var results = [];
var result;
result = func;
results.push(func);
for(var i = 0;i < n - 1; i++){
results.push(results[i] * 2);
}
return results;
};
// var doubleIterator = createIterator(getDouble(3),2).slice(-1).pop();
Here is the function that I am trying to make to have only 1 call. Everything is working properly above but I must be able to submit this entire response only passing one parameter this this function:
function doubleIterator(d){
// var n;
// createIterator.call(this,n)
return createIterator(getDouble(d),n).slice(-1).pop();
}
console.log(doubleIterator);
You could use this definition of createIterator:
function createIterator(func, n) {
return function (arg) {
for (var i = 0; i < n; i++) arg = func(arg);
return arg;
};
}
function getDouble(num){
return num * 2;
}
var doubleIterator = createIterator(getDouble, 2);
console.log(doubleIterator(3)); // => 12
You could also write the same with reduce and bind:
function createIterator(func, n) {
return [].reduce.bind([...Array(n)], arg => func(arg));
}
function getDouble(num){
return num * 2;
}
var doubleIterator = createIterator(getDouble, 2);
console.log(doubleIterator(3)); // => 12
Although shorter code, it is a bit obscure. It binds this and the first argument of reduce as follows:
this: an empty array of n elements, which dictates how many times the callback function (i.e. the second argument, see below) is called. The actual values in the array are not important, as the callback function being used ignores them:
callback function arg => func(arg): will be called n times when the reduce is actually invoked (which does not happen here yet). Although the callback function could accept the array value as second argument, there is no interest to do so.
The third argument is left unbound, and determines the initial value with which the callback function will be called the first time. So createIterator returns a variant of reduce that accepts only one argument, which is the initial value.
Note that there is one harmless difference compared to the first snippet: if you call the function, that is returned by createIterator, without argument, the function func is called one time less here (with undefined as argument, just like in the first snippet); this is because of how reduce works when you don't pass it an initial value.

How is passing an anonymous function as an argument internally used?

I've encountered some code that I'm having trouble fully understanding. The principles seem clear enough, but I'm having some difficulty with the second argument that's declared in the forEach function call. Clearly the anonymous function is passed into forEach via the action argument, but how exactly does it work once inside the for loop?
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
var numbers = [1, 2, 3, 4, 5], sum = 0;
forEach(numbers, function(number) {
sum += number;
});
console.log(sum); // 15
I think what confuses me most is that the syntax of the anonymous function doesn't seem compatible with action(array[i]) - I mean, I understand that sum acquires each value of the array in turn, but if the function "replaces" the action argument, how and where does the (array[i]) part fit in?
Let me rewrite that code in a more explicit way:
function forEach(array, action) { //1st parameter is an array, the 2nd is a function
for (var i = 0; i < array.length; i++)
action(array[i]); //The function is used, with each element of the array as parameter
}
var numbers = [1, 2, 3, 4, 5], sum = 0;
var myFunction= function (number) { //I declare a function which receives a number
sum += number; //and adds it to sum.
}
forEach(numbers,myFunction); //I call the forEach function using the
// variables I previously created as parameters
console.log(sum);
In javascript when you define a variable you write:
var x = 0; // here you reserve an object
And when you define a function also you reserve an object. Javascript deal with functions as objects and you can assign it to any variable:
var x = function(number){ sum +=number; };
forEach (numbers, x(number) );
And about the confused syntax, Anonymous functions are functions that are dynamically declared at runtime. They’re called anonymous functions because they aren’t given a name in the same way as normal functions.
So to call an Anonymous function you follow this syntax:
// call
function (param1, param2, ...){
// function body
}
if you want to call it again either you should repeat the code above or declare a function without calling it and save it on variable where you can call it many times:
// declaration
var x = function(param1, param2, ...){
// body
};
// call
x(p1,p2,....);

Passing array of functions to another function

I'm trying to pass arbitrary number of arguments to function. The arguments should be json type [function : arrayOfArgs]. The keys are functions and the values are arrays of the arguments, that should be passed to those functions.
At first, I considered function with only a number of argument
function _gl(f,args){ f.apply(null,args); }
function func(a,b){ alert(a+b); }
//calling the function
<input type="button" value="test" onclick="_gl(func,['2','3']);"/>
and it works pretty good .Now I'm trying to generalize that method
function _GL(){
var arguments = _GL.arguments;
var i=0;
for(i;i<arguments.length;i++)
{
var A=arguments[i];
for(j in A) j.apply(null,A[j]);
}
}
//and calling it
<input type="button" value="TEST" onclick="_GL({func:['2','3']});"/>
but i'm getting the following error "Uncaught TypeError: Object func has no method 'apply' ".
You can use this code jsFiddle:
_GL = function() {
var arguments = _GL.arguments;
var i = 0;
for (i = 0; i < arguments.length; i++) {
var arg = arguments[i];
for (j in arg) {
var f = window[j];
f.apply(null, arg[j]);
}
}
};
As you can see you have to get your function f first from the window element by its name. Then f has the right type an args can be applied.
{func:['2','3']}
You are making an object with a (string) key called "func" with value ['2','3']. Strings are not functions, so it doesn't have .apply().
In objects, your keys must be strings, you cannot use other types as keys.
To "generalize" it, you should pass it an array of functions and their arguments. Something like this:
[[func, ['2','3']], [func2, ['abc']]
So, if you did this:
onclick="_GL([[func, ['2','3']], [func2, ['abc']]);"
Then you could loop through and get the functions and call 'em.
function _GL(funcs){
for(var i=0, len=funcs.length; i < len; i++){
var func = funcs[i];
func[0].apply(null, func[1]);
}
}
One possible solution;
var _gl = function (callables) {
// Loop through each property in the passed in object
for (var fnName in callables) {
// Only apply for properties that is local to `callables`
if (callables.hasOwnProperty(fnName)) {
window[fnName].apply(callables[property]);
}
}
};
... onclick='_gl({"MyFunction": ["a", 1, []]});' ...
Instead of using the global namespace, you could (and should!) set up an object with your callable functions.

how to create functions with variable arguments in javascript?

I want to create a function in javascript with a variable amount of arguments. The next example is how I want to call this function:
myFunction(1,2);
myFunction(1,2,3);
myFunction(1,2,3,4);
myFunction(1,2,3,4,5);
myFunction(1,2,3,4,5,6);
Anyone knows how to define this function?
You can access the arguments by their ordinal position without the need to state them in the prototype as follows:
function myFunction() {
for (var i = 0; i < arguments.length; i++)
alert(arguments[i]);
}
myFunction(1, 2, "three");
>>1
>>2
>>three
Or if you really are passing in a set of semantically related numbers you could use an array;
function myFunction(arr) { ... }
result = myFunction([1,2,3]);
Latest update
Rest parameters are supported in all new browsers.
Check here for details
The rest parameter syntax allows us to represent an indefinite number of arguments as an array, which you can pass it to other functions too.
function myFunction(...data){
console.log(...data);
myOtherFunction(...data);
}
myFunction(1,2,3); //logs 1,2,3
myFunction([1,2,3]); //logs [1,2,3]
Use the 'arguments' variable like this :
function myFunction() {
alert(arguments.length + ' arguments');
for( var i = 0; i < arguments.length; i++ ) {
alert(arguments[i]);
}
}
Call the methods as you did before
myFunction(1,2);
myFunction(1,2,3,4,5,6);
Just refer to the arguments array.
https://developer.mozilla.org/en/JavaScript/Reference/functions_and_function_scope/arguments
If an argument is not present, use the default. Like this...
function accident() {
//Mandatory Arguments
var driver = arguments[0];
var condition = arguments[1]
//Optional Arguments
var blame_on = (arguments[2]) ? arguments[2] : "Irresponsible tree" ;
}
accident("Me","Drunk");
As an add-on: You can assign values to the unnamed function parameters, as in (german wiki)
arguments[0] = 5;

Passing arbitrary number of parameter to a function in javascript

I would like to write a javascript function that works something like this...
f([["a"]], function(e){alert(e);});
// results in alert("a");
f([["a"], ["b"]], function(e1,e2){alert(e1 + ":" + e2);});
//results in alert("a:b");
f([["a", "b"], ["c"]], function(e1,e2){alert(e1 + ":" + e2);});
//results in alert("a:c");alert("b:c");
I can think of a recursive solution for the looping, but how do I send a "unknown" number of variables to a function?
If you put all your arguments into an array (lets call it foo), you can call a function fn with those arguments by using the apply-function.
fn.apply(null, foo)
The first argument (null in this case) is whatever you want this to be inside of the called function. null will probably work for you.
According to this page, you can access any/all arguments using the arguments variable:
function f() {
for( var i = 0; i < arguments.length; i++ ) {
//do something with arguments[i]
}
}
[EDIT]
Now that I understand what you're trying to do, here's a (dirty) way to do it:
Seriously, don't do it this way. It's horrible. Puppies will die.
function f(arr, fn) {
var s = "fn(";
for( var i = 0; i < arr.length; i++ ) {
//you can implement your recursive code here if you like; I'm just doing the base cases
s += arr[i];
if(i+1 < arr.length) {
s += ",";
}
}
s += ");";
eval(s);
}
And for a cleaner way:
function f(arr, fn) {
fn.apply(this, arr);
}
Within the function you can use the variable arguments to see what was passed. IE
function blah() {
console.log(arguments);
}
blah(1, 2); // [1, 2]
blah([1, 2], [3]); // [[1,2], [3]]
blah(1, [2, 3], "string"); // [1, [2, 3], "string"]
You can use the arguments variable that each function has to go through all the passed in arguments.
function myConcat(separator) {
var result = ""; // initialize list
// iterate through arguments
for (var i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
See this article for a discussion of variable number of arguments.
You can use the arguments pseudo-array available within the function to get the arguments passed in without declaring them explicitly (i,e. regardless of whether you define an argument for a function, you can access everything passed in to the function via the arguments implicit variable within that function).

Categories