JavaScript "arguments" -passing a function with other parameters - javascript

Function multiply below is passed a callback function "addOne". Function multiply returns [3,5,7].
Since the callback function addOne is one of the arguments of function multiply, and since the arguments of function multiply are all multiplied by 2, why doesnt the callback function itself (i.e. addOne) get multiplied by 2? In other words, instead of function multiply returning [3,5,7], I would have expected it to return [3,5,7, NAN] since the function is not a number?
Does JavaScript interpreter just somehow know not to multiply it by 2?
function addOne(a) {
return a + 1;
}
function multiply(a,b,c, callback) {
var i, ar = [];
for (i = 0; i < 3; i++) {
ar[i] = callback(arguments[i] * 2);
}
return ar;
}
myarr = multiply(1,2,3, addOne);
myarr;

Because your loop's condition is <3 (hehe) which means it won't subscript the callback (the last element).
You should consider making the callback the first argument always, and splitting the arguments like so...
var argumentsArray = Array.prototype.slice.call(arguments),
callback = argumentsArray.shift();
jsFiddle.
Then, callback has your callback which you can call with call(), apply() or plain (), and argumentsArray has the remainder of your arguments as a proper array.

This line for (i = 0; i < 3; i++) { is protecting you.
You stop before it hits the callback argument

Because you are running the the loop for the first 3 args only. i < 3 runs for i=0, i=1,i=2

Related

Where does a function receive its input when passing the function as an argument?

I have the following code:
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);
Where does the function(number){ sum += number; } receive its arguments when passed? Does the resulting function look like this?
function(array[i]){sum += array[i]}
The normal way: Between the parenthesis when it gets called.
action(array[i]);
^^^^^^^^
Where does the function(number){ sum += number; } receive its arguments when passed?
You have created a function expression and passed it as an argument to the function (forEach). That function has one argument. It could be used while calling it.
action(array[i]);
//array[i] will be received as an argument to the passed function expression
Inside forEach function action would be a function reference. And that function reference is capable of passing one known parameter. So you can call it in anyways you want.

How does a function gets passed in to another function?

I have a forEach function defined to do "something" with all the items in an array:
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
var numbers = [1, 2, 3, 4, 5], sum = 0;
So I could do:
forEach(numbers, console.log);
And it would print out all the numbers because 'console.log(array[i])' prints the number to the console.
I get that part.
Here's where I'm stuck: If I pass the function below into the place of the action parameter, instead of 'console.log' then at what point does the function know about every element?
forEach(numbers, function(number) {
sum += number;
});
console.log(sum);
// 15
How does it get evaluated? If I pass console.log into the last problem and it still has to be evaluated as 'console.log(array[i])' with the '(array[i])' code next to whatever parameter is being passed in, then doesn't that get applied to the entire function too since that function is the parameter? Such as below:
function(number) { sum += number; }(array[i])
at what point does the function know about every element
At no point (just like when you pass in console.log).
The forEach function calls it on this line:
action(array[i]);
At which point, it only knows about a single value from the array because that is all that is passed into it.
(It also knows about the sum variable because that is defined in a wider scope than the function).
How does it get evaluated?
It creates a new scope (with array, action and i variables) and assigns the function to the action variable - that's a function invocation.
Your
var sum = 0;
forEach([1, 2, 3, 4, 5], function(number) {
sum += number;
});
is just the same as
var sum = 0;
{ // let's assume block scope here
var array = [1, 2, 3, 4, 5],
action = function(number) {
sum += number;
},
i;
for (i = 0; i < array.length; i++)
action(array[i]);
}
If I pass console.log into the last problem and it still has to be evaluated, then doesn't that apply to the entire function too since that function is the parameter?
Yes, exactly. You are passing a function object - and whether get that by referencing the console.log variable or by creating it on the fly (with the function expression) doesn't matter to forEach. It only will get executed with action(…) - where the array[i] value is passed for the number parameter of your function.
In JavaScript, functions are first-class citizens. That means they can be treated as variables, just like strings, numbers, etc.
When you do:
forEach(numbers, function(number) {
sum += number;
});
You are passing forEach an anonymous function. Instead of the function being in a variable, it's created on-the-fly. Inside your forEach function, action will contain your anonymous function.
In for for loop, the action function is called for each element.
Heres the solution to your problems:
function forEach(array, action) {
for (var i = 0; i < array.length; i++){
if(typeof action == 'function'){
action(array[i]);
}else{
var slices = action.match(/(.+)\.([a-zA-Z0-9]+)/);
var object = eval(slices[1]);
var action = slices[2];
object[action](array[i]);
}
}
}
I've tested it with both scenarios and it works like magic

Javascript: Compose a function with argument placement instructions for each composition

I'm looking for a javascript function that can:
Condition (I)
compose another function when it does not have recursion in its definition, kind of like in maths when the function is given a power, but with multiple arguments possible in the first input - e.g. with a (math) function f:
f(x) := x+2
f5(x) = f(f(f(f(f(x))))) = x+10
Condition (II)
Or maybe even input custom arguments into each step of composition:
(52)2)2=
Math.pow(Math.pow(Math.pow(5,2),2),2) = Math.pow.pow([5,2],2,["r",2]])
//first arg set, how times the next, 2nd arg set - "r" stands for recursion -
//that argument will be occupied by the same function
//Using new solution:
_.supercompose(Math.pow,[[5,2],[_,2],[_,2]]) //-> 390625
2((52)3)=
Math.pow(2,Math.pow(Math.pow(5,2),3)) = Math.pow.pow([5,2],["r",2],["r",3],[2,"r"])
//Using new solution:
_.supercompose(Math.pow,[[5,2],[_,2],[_,3]]) //-> 244140625
_.supercompose(Math.pow,[[5,2],[_,2],[_,3],[2,_]]) //-> Infinity (bigger than the max. number)
Note: The above are just templates, the resulting function doesn't have to have the exact arguments, but the more close to this (or creative, for example, a possibility of branching off like this ->[2,4,"r",4,2,"r"], which would also be complicated) the better.
I've been attempting to do at least (I) with Function.prototype, I came up with this:
Object.defineProperty(Function.prototype,"pow",{writable:true});
//Just so the function not enumerable using a for-in loop (my habit)
function forceSlice(context,argsArr)
{returnArray.prototype.slice.apply(context,argsArr)}
Function.prototype.pow = function(power)
{
var args=power<2?forceSlice(arguments,[1]):
[this.pow.apply(this,[power-1].concat(forceSlice(arguments,[1])))];
return this.apply(0,args);
}
//Usage:
function square(a){return a*a;}
square.pow(4,2) //65536
function addThree(a,b){return a+(b||3); }
// gives a+b when b exists and isn't 0, else gives a+3
addThree.pow(3,5,4) //15 (((5+4)+3)+3)
Worst case, I might just go with eval, which I haven't figured out yet too. :/
Edit: Underscore.js, when played around with a bit, can fulfill both conditions.
I came up with this, which is close to done, but I can't get it to work:
_.partialApply = function(func,argList){_.partial.apply(_,[func].concat(argList))}
_.supercompose = function(func,instructions)
{
_.reduce(_.rest(instructions),function(memo,value)
{
return _.partialApply(_.partialApply(func, value),memo)();
},_.first(instructions))
}
//Usage:
_.supercompose(Math.pow,[[3,2],[_,2]]) //should be 81, instead throws "undefined is not a function"
Edit: jluckin's cleareance of terms (recursion-> function composition)
Edit: made example function return number instead of array
The term you are looking for is called function composition, not necessarily recursion. You can apply function composition in javascript easily since you can pass a function as an argument.
I created a small function called compose, which takes a function, an initial value, and the number of times to compose the function.
function compose(myFunction, initialValue, numberOfCompositions) {
if (numberOfCompositions === 1) {
return myFunction(initialValue);
}
else {
return compose(myFunction, myFunction(initialValue), --numberOfCompositions);
}
}
When this function is evaluated, you pass in some function f(x), some initial x0, and the repeat count. For example, numberOfCompositions = 3 gives f(f(f(x)));
If there is one composition, then f(x) is returned. If there are two compositions, compose returns f(x) with f(x) replacing x as the argument, with 1 passed in as the composition so it will evaluate f(f(x)).
This pattern holds for any number of compositions.
Since functions are treated as objects and can be passed as arguments of functions, this method basically wraps your "non-recursive" functions as recursive functions to allow composition.
Success(simplicity wins):
_.supercompose = function (func,instructions,context)
{
var val;
for(var i = 0; i < instructions.length; i++)
{
val = _.partial.apply(_,[func].concat(instructions[i])).apply(context||this,val?[val]:[]);
}
return val;
}
//Usage (with a function constructor for operations):
_.op = function(o){return Function.apply(this,"abcdefghijklmnopqrstuvwxyz".split("").concat(["return " + o]))}
_.op("a+b")(3,5) //-> 8
_.op("a*b")(3,5) //-> 15
_.supercompose(_.op("(a+b)*c*(d||1)"),[[1,2,3],[-5,_,1],[1,2,_,3]])
//-> (1+2)*((-5+((1+2)*3))*1)*3 -> 36

Passing Variable Number of arguments in javascript function argument-list

Can I pass a variable number of arguments into a Javascript function? I have little knowledge in JS. I want to implement something like the following:
function CalculateAB3(data, val1, val2, ...)
{
...
}
You can pass multiple parameters in your function and access them via arguments variable. Here is an example of function which returns the sum of all parameters you passed in it
var sum = function () {
var res = 0;
for (var i = 0; i < arguments.length; i++) {
res += parseInt(arguments[i]);
}
return res;
}
You can call it as follows:
sum(1, 2, 3); // returns 6
Simple answer to your question, surely you can
But personally I would like to pass a object rather than n numbers of parameters
Example:
function CalculateAB3(obj)
{
var var1= obj.var1 || 0; //if obj.var1 is null, 0 will be set to var1
//rest of parameters
}
Here || is logical operator for more info visit http://codepb.com/null-coalescing-operator-in-javascript/
A Is there a "null coalescing" operator in JavaScript? is a good read
Yes, you can make it. Use variable arguments like there:
function test() {
for(var i=0; i<arguments.length; i++) {
console.log(arguments[i])
}
}

How String.concat() implements in javascript?

In function .concat(), I can pass an arbitrary number of arguments to it.
I understand function overloading in C++, but I don't know how implement a function with unknown number of arguments in JavaScript.
How do I implement an arbitrary number of arguments to a function?
In javascript, you would use the built in parameter called "arguments" which is an array of all the arguments passed to the function. You can obtain it's length with arguments.length and each value from the array arguments[0], arguments[1], etc... Every function has this built in variable that you can use.
For example, a function to concatenate all strings passed to it.
function concatAll() {
var str;
for (var i = 0 ; i < arguments.length; i++) {
str += arguments[i];
}
return(str);
}
var f = concatAll("abc", "def", "ghi"); // "abcdefghi"
You can do this using the arguments object. See the examples and documentation here: https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments
Like this -
function f()
{
var i;
for(i=0; i<arguments.length; i++)
{
alert( (i+1) + "th argument: " + arguments[i]);
}
}
All the functions in javascript has a built-in parameter called arguments which is an array containing all the function arguments passed to the function. Just iterate over this array and you will be able to access all the arguments of a function.
As an example, once I've written a function which is used to enable/disable certain button if some specific fields were not empty. I wrote this function this way -
function toggleButton() // I used jquery inside this function
{
var i;
var last = arguments.length-1;
for(i=0; i<last; i++)
{
if( $.trim($(arguments[i]).val()) === "" )
return false;
}
$(arguments[last]).toggle();
return true;
}
and called this function like this -
toggleButton("#idOfFirstField", "#idOfSecondField", "#idOfButtonToToggle");
or like this -
toggleButton("#idOfFirstField", "#idOfSecondField", "#idOfThirdField", "#idOfButtonToToggle");
so in both the cases, I was passing variable number of field ids to the function and it checked that if these fields were empty. If all of them contained some value, then it toggled the visibility of the button.
Like this - use the arguments object all functions have available :
function someFunction() {
for (var i=0,n=arguments.length;i<n;i++) {
// do something with arguments[i];
}
}
You can use the arguments array to access parameters that are not formally declared inside the function:
function printArguments() {
for (i = 0; i < printArguments.arguments.length; i++)
document.writeln(printArguments.arguments[i] + '<br />');
}
printArguments(1, 2, 3, 'etc');
Source: http://www.irt.org/articles/js008/
Any javascript function can have an arbitrary number of arguments. If function execution depends on the number or specific qualities of it's arguments, you'll have to check the arguments object, which can be iterated like an 'Arraylike' object, as others have shown.
In some cases it may be handy to convert the arguments to a real array, using something like
var args = Array.prototoype.slice(arguments).
Here's a blog entry from John Resigs page on method overloading that may interest you.

Categories

Resources