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.
Related
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].
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,....);
I wanted to do a partial_left function that will be executed into an array, something liek that:
array_1.map(partial_left1(equal));
function equal(x){return x;}
, but I crushed when I pushed the variables of arguments into an other array(and not with the Array.prototype.slice.call(arguments)). Because I wanna do other way, But I surprised when the result were differents:
var array_1=[1,2,3];
with my method: th result is : [1,1,1]//doing reference only to the array[0]
with Array,prototype.slice.call: [1,2,3]//how I would want to be
this is my code, where I push the values of arguments in another array:
function concat(arg1,arg2,n){
for (var i = n; i < arg2.length; i++)
arg1.push(arg2[i]);
return arg1;
}
function partial_left1(f){
var argum_apply=[];
argum_apply=concat(argum_apply,arguments,1);
return function(){
argum_apply=concat(argum_apply,arguments,0);
return f.apply(this,argum_apply);
};
}
And this is the code with Array.prototype.slice.call:
function array(a, n) { return Array.prototype.slice.call(a, n || 0); }
function partial_left2(f /*, ...*/) {
var args = arguments;
return function() {
var a = array(args, 1);
a = a.concat(array(arguments));
return f.apply(this, a);
};
}
A simple definition of equal with partial:
var equal_left1=partial_left1(equal);
var equal_left2=partial_left2(equal);
Here are the results, and I don't know why they are differents?
var array_1=[1,2,3];
alert(array_1.map(equal_left1));//1,1,1
alert(array_1.map(equal_left2));//1,2,3
Someones who knows please explain me what are the differences between "Concat" and use "Array.prototype.slice.call"?
One of the bad design decisions: arguments is not an array. It is array-like, in the sense it has a length property.
You can't call the concat method of arguments because it doesn't exist.
Array.prototype.slice.call uses the slice method from the arrays and invokes it -- it is a quick and easy way to turn something array-like to a proper array.
You can do the same thing with a loop, if you want:
var arr = [];
for (var i = 0; i < arguments.length; i++) {
arr[i] = arguments[i];
}
How to create method twice? I can't understand how to change this in body of function. Why it doesn't work?
function twice() {
var buf = [];
for ( var i = 0; i < this.length; i++ ) {
buf.push(this[i]);
}
for ( var i = 0; i < this.length; i++ ) {
buf.push(this[i]);
}
this = buf;
}
Array.prototype.twice = twice;
a = [1,2,3];
a.twice();
a; // [1,2,3,1,2,3]
I can't understand how to change this in body of function
If you mean the value of this, you can't. But you don't have to for what you're doing
You're very close, you just have a fair bit to remove:
function twice() {
var i, l;
for (l = this.length, i = 0; i < l; ++i) {
this.push(this[i]);
}
}
Remember, your array is an object. To change its contents, you just change its contents, you don't have to change the reference to it.
Note, though, that you can use this trick on any modern browser:
function twice() {
this.push.apply(this, this);
}
That works by using the Function#apply function, which calls the function you call it on (so, push in our case) using the first argument you give it as the object to operate on, and the second argument as the arguments to pass into that function (which it takes as an array). More on MDN and in the spec. It happens that push allows you to pass it an arbitrary number of arguments, and will push each one in order. So if you're trying to add the contents of the array to the array a second time, that one line will do it (on modern browsers, some older IE implementations don't like this use of push.apply).
You cannot assign a value to this. That's the rules. But you can modify the value of this. Try pushing some values into this.
function twice() {
var len = this.length;
for (var i = 0; i < len; i++) {
this.push(this[i]);
}
}
Array.prototype.twice = twice;
a = [1, 2, 3];
a.twice();
alert(a);
Here's a fiddle. http://jsfiddle.net/Qvarj/ As you can see, most of the logic is yours.
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;