I have functions, to pass the parameters from a to b.
but it seems the apply just access 2 parameters
function a(){
var p1=1;
var p2=2;
b.apply(this,arguments);
}
function b(){
//so how to get p1,p2 in this function?
console.log(arguments);
}
a(3,4);
so how to pass the p1 p2 in function a and get 1,2,3,4 in functionb?
You create an array with all the parameters you need to pass:
var combinedArray = [p1, p2].concat(Array.prototype.slice.call(arguments));
this function:
Creates an array with first 2 elements as p1 and p2
And appends the arguments array to it.
Then you can call it as b.apply(this, combinedArray)
PS:
The Array.prototype.slice.call(arguments) is used to convert arguments object to a real array.
In order to pass your variables to another function you have to add them to the array you provide to apply. But you can not add them directly to the arguments variable since it's not the real array. So first of all you have to build a new array which you would pass to apply. You can transform arguments to array by var newArray = Array.prototype.slice.call(arguments); - this creates new array from arguments. Now you can act with it as with regular array (newArray.push(p1); or newArray = newArray.concat([p1, p2]); and so on). And then just pass this array to apply instead of arguments.
So your code would change this way:
function a(){
var p1=1;
var p2=2;
var argumentsArray = Array.prototype.slice.call(arguments);
b.apply(this, argumentsArray.concat([p1, p2]));
}
function b(){
console.log(arguments);
}
a(3,4); // output: [3, 4, 1, 2];
If you need to prepend p1 and p2 you can use unshift
Try this code.
void temp() {
var animals = ["cat", "dog", "horse", "cow"];
animals.forEach(function (eachName, index) {
console.log(index + 1 + ". " + eachName);
});
}
Related
I know arguments is an array-like object in every function, but I'm not sure why we need it and how we use it? Below is one example that confused me...
So here why we can't simply put var args=[], instead, use slice on arguments?
(im not sure if it is a good example to explain arugments, but im also trying to understand how the apply() works here...)
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){
return func.apply(null, args);
}, wait);
};
.apply() allows you to call a function while specifying two different things:
The value of the this pointer inside the function call.
A set of arguments to pass to the function when your source of the arguments is an array.
One will typically use .call() if the number of arguments to pass to the function is known in advance and will typically use .apply() when the number of arguments is not know in advance and thus the arguments are in an array or can be put into an array.
Presumably, slice() in the code example you show is Array.prototype.slice so that code example is grabbing the set of arguments AFTER the first two and putting them into their own array so that they can then be passed to the original function.
The arguments object in Javascript is "array-like". It has a .length property and is zero indexed like an array, but it does not have any array methods on it. So, if you want to use an array method on it like .slice() to copy some elements to a new array, you have to manually specify array methods from the Array prototype rather than directly use .slice() on the arguments object.
So, if you called:
function myFunc(a, b, c, d) {
// four arguments present here
}
_.delay(myFunc, 100, 1, 2, 3, 4);
The inner workings of _.delay() would skip the first two arguments passed to it (because those are for use directly in _.delay() and get just the remaing last four arguments and then pass those to the callback function using .apply().
Here's a working snippet example:
var _ = {};
var slice = Array.prototype.slice;
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){
func.apply(null, args);
}, wait);
};
function myFunc() {
log("number of arguments passed to myFunc(): " + arguments.length);
log(JSON.stringify(slice.call(arguments)));
}
_.delay(myFunc, 500, 1, 2, 3, 4)
function log(x) {
var div = document.createElement("div");
div.innerHTML = x;
document.body.appendChild(div);
}
This code will get any arguments after the first 2, and put them in a new array. If you set it to a blank array, you will not have any arguments that may have been passed in addition to the named ones.
Consider the difference between the following 2 snippets:
var slice = Array.prototype.slice;
function test(a, b) {
var args = slice.call(arguments, 2);
console.log(args);
}
test(1, 2, 3, 4);
Console Output:
[3, 4]
function test(a, b) {
var args = [];
console.log(args);
}
test(1, 2, 3, 4);
Console Output:
[]
It is necessary to call slice on the arguments array, because the arguments object is only array-like, and does not include this method.
Consider:
Primitive data types are passed by value in JavaScript. This means
that a copy is effectively made of a variable when it is passed to a
function, so any manipulation local to the function leaves the
original variables untouched.
function fiddle(arg1) {
arg1 = "Fiddled with";
console.log("In function fiddle str = "+arg1+"<br>");
}
var str = "Original Value";
console.log("Before function call str = "+str+"<br>");
fiddle(str);
console.log("After function call str ="+str+"<br>");
EASY
composite types such as arrays and objects if used, they are passed
by reference rather than value
Consider the following modification
of the previous fiddle() function:
function fiddle(arg1) {
arg1[0] = "Fiddled with";
console.log("In function fiddle arg1 = "+arg1+"<br>");
}
var arr = ["Original", " Original ", " Original "];
console.log("Before function call arr = "+arr+"<br>");
fiddle(arr);
console.log("After function call arr ="+arr+"<br>");
FINE till here
From here I find myself really confused,
function fiddle(arg1) {
arg1 = ["Blasted!","Blasted!"];
console.log("In function fiddle arg1 = "+arg1+"<br>");
}
var arr = ["Original", " Original ", " Original "];
console.log("Before function call arr = "+arr+"<br>");
fiddle(arr);
console.log("After function call arr ="+arr+"<br>"); // Why this hasn't changed?
Any suggestion? And will it be OK to say
composite types such as arrays and objects if used, they are passed
by reference rather than value
in this case too?
Seems pretty clear, inside fiddle you're overwriting the reference to arr with an array you created on the spot. You never touched arr itself through its reference, just the reference, so once you're outside again, arr is still the original array.
That is because the bracket notation (for arrays) or the dot notation (for objects) allows you to mutate objects within an array/object, which will propagate up and outwards the scope of the function as they are passed by reference, even though the "parent" object is passed by value. This feature is known as call-by-sharing, as addressed in a previous question. In short:
Everything is passed by value, but...
Objects within the "everything" (if exists, i.e. for arrays and objects) is passed by reference
If you want to modify arr outside of the scope of the fiddle() function, you will have to return it, i.e.: return arr1; and then assign arr = fiddle(arg1[,arg2,...]), like as follow:
function fiddle(arg1) {
arg1 = ["Blasted!","Blasted!"];
$('body').append("In function fiddle arg1 = "+arg1+"<br>");
return arg1;
}
var arr = ["Original", " Original ", " Original "];
$('body').append("Before function call arr = "+arr+"<br>");
arr = fiddle(arr);
$('body').append("After function call arr ="+arr+"<br>"); // Why this hasn't changed?
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I've found this topic which I've implemented (see accepted answer):
javascript equivalent of PHP's call_user_func()
However, I am having a problem with multiple parameters. I realize what I was doing was turning my parameters into strings and treating it like 1 parameter, but I don't know how to fix this because I am dynamically creating the parameters.
Meaning, I have defined in my code the following:
var a = new Array();
a[0] = new Array();
a[0][0] = 'alert';
a[0][1] = '\'Hello World\'';
a[1] = new Array();
a[1][0] = 'setTimeout';
a[1][1] = 'alert("goodbye world")';
a[1][2] = '20';
Later, I was calling them like this:
var j = 0;
var len = 0;
var fx = '';
var params = '';
for( i in a ){
params = '';
len = a[i].length;
fx = a[i][0]; // getting the function name
a[i].splice( 0, 1 ); // removing it from array
if( len > 1 ){
params = a[i].join(", "); // trying to turn the parameters into the right format, but this is turning it into strings I think
params = params.replace(/\\'/g,'\''); // bc i was adding slashes with PHP
}
window[fx](params);
}
I don't have to use arrays to do this. I don't understand JS OOP (haven't tried yet), though I am comfortable with PHP OOP, so I don't know if there is a way to do this there.
Any help on passing multiple parameters would be appreciated.
Thanks.
First thing to do: Scrap your entire code, start over. Your approach will not get you anywhere where you'd want to be. (Unfortunately I can't tell you where you'd want to be because I cannot make sense of your example.)
There are three ways to call a function in JavaScript.
function foo() { console.log(arguments); }
// 1. directly
foo(1, 2, 3);
// 2. trough Function.call()
foo.call(this, 1, 2, 3);
// 3. trough Function.apply()
var args = [1, 2, 3];
foo.apply(this, args);
call and apply are similar. They let you decide which object the this keyword will point to inside the function (that's the important bit!).
apply accepts an array of arguments, call accepts individual arguments.
The closest thing to call() is PHP's call_user_func(). The closest thing to apply() is PHP's call_user_func_array().
JavaScript objects share something with PHP arrays: They are key/value pairs.
// an anonymous function assigned to the key "foo"
var obj = {
foo: function () { console.log(arguments); }
};
This means you can access object properties either with the dot notation:
// direct function call
obj.foo(1, 2, 3);
Or through square bracket notation (note that object keys are strings):
var funcName = "foo";
obj[funcName](1, 2, 3);
obj[funcName].call(obj, 1, 2, 3);
obj[funcName].apply(obj, [1, 2, 3]);
Square bracket notation gives you the freedom to choose an object property dynamically. If this property happens to be a function, apply() gives you the freedom to choose function arguments dynamically.
Every top-level function that has not been declared as the property of some object will become the property of the global object. In browsers the global object is window. (So the function foo() in my first code block above really is window.foo.)
Note that this does not work like in PHP. It will point to the object the function has been called on, not the object the function "belongs to". (The concept "belongs to" does not really exist in JavaScript. Things can be modeled that way, but it's only a convention.)
With direct calling (obj.foo(1, 2, 3)), this will point to obj. With call and apply, this will point to whatever object you want to. This is a lot more useful than it sounds at first. Most of the time when you want to call functions dynamically, you will end up using apply.
Check out Function.apply:
function test(a, b) { console.log([a, b]) }
test.apply(null, [1, 2]); // => [ 1, 2 ]
Late to the party, but now with ES6 you can simply do
function FunctionX(a,b,c,d){
return a + b + c + d;
}
let fx = "FunctionX";
let params = [ 1, 10, 100, 200 ];
let answer = window[fx]( ... params);
let answer2 = globalThis[fx]( ... params ); // this is more cross-platform
to unpack your argument array
I need a method that can have an arbitrary number of parameters. In C# we have the params statement. Do we have anything similar in JavaScript?
There is the arguments collection, which contains all arguments passed to the function.
There is a) no need to specify "optional" arguments in the function signature and b) any function accepts any number of parameters.
function foo() {
console.log(arguments);
}
foo(1,2,3,4); // logs [1, 2, 3, 4]
Likewise, there is no need to supply "required" arguments in a function call:
function foo(a, b, c, d) {
console.log(arguments);
}
foo(1,2); // logs [1, 2]
Any argument named in the signature but not supplied in the function call will be undefined.
Note that arguments behaves like an Array, but technically it isn't one. For example, you can call arguments[0], but you can't call arguments.slice(). What you can do to get around this is using the Array prototype:
Array.prototype.slice.call(arguments, 1, 2);
The so-called rest parameter ... is a new (ES6+) addition to the language and makes working with variadic functions more comfortable. #ArunCM's answer explains it.
I know this thread is too old but I believe something is missing here.
There is Rest parameter (introduced in ECMAScript 6) which will allow us to represent an indefinite number of arguments as an array.
It always returns an array. Which means even in defensive JavaScript land, it’s ok to do things like check .length of rest without guards.
Syntax :
function(a, b, ...theArgs) {
// ...
}
There are three main differences between rest parameters and the arguments object:
rest parameters are only the ones that haven't been given a separate name, while the arguments object contains all arguments passed to the function
the arguments object is not a real array, while rest parameters are Array instances, meaning methods like sort, map, forEach or pop can be applied on it directly;
the arguments object has additional functionality specific to itself (like the callee property).
Additional reading : Spread
function f(x, ...y) {
// y is an Array
return x * y.length;
}
console.log("Expected result : 3*2 = 6 & Actual result : " + f(3, "hello", true));
console.log("Expected result : 3*4 = 12 & Actual result : " + f(3, "a", true, "b", 1));
//here we are not passing anything to "y" but its still safe to check .length of "y" because it always return an array.
console.log("Expected result : 3*0 = 0 & Actual result : " + f(3));
Yes. arguments.
function concatStrings () {
var str = '';
for (var i = 0; i < arguments.length; i++) {
str += arguments[i];
}
return str;
}
Be aware that arguments isn't an array, so it doesn't have methods like join or push. It's just an array-like object (with numerical properties and a length property) so it can be iterated through.
JavaScript has arguments object inside functions. It contains of all params passed to the function.
More info
It is some sort of implicit in the special variable "arguments". Use like this:
function something(arg1, arg2) {
for (var i = 0; i < arguments.length; i++) {
var x = arguments[i];
}
}
Then you can call it like something(1, 2, 3, 'a', 'b', 'c')
More examples here: http://www.jtricks.com/javascript_tutorials/varargs.html
Javascript functions can accept any number of parameters by default. You can see them with the arguments variable.
See here.
this.String = {
Get : function (val) {
return function() {
return val;
}
}
};
What is the ':' doing?
this.String = {} specifies an object. Get is a property of that object. In javascript, object properties and their values are separated by a colon ':'.
So, per the example, you would call the function like this
this.String.Get('some string');
More examples:
var foo = {
bar : 'foobar',
other : {
a : 'wowza'
}
}
alert(foo.bar); //alerts 'foobar'
alert(foo.other.a) //alerts 'wowza'
Others have already explained what this code does. It creates an object (called this.String) that contains a single function (called Get). I'd like to explain when you could use this function.
This function can be useful in cases where you need a higher order function (that is a function that expects another function as its argument).
Say you have a function that does something to each element of an Array, lets call it map. You could use this function like so:
function inc (x)
{
return x + 1;
}
var arr = [1, 2, 3];
var newArr = arr.map(inc);
What the map function will do, is create a new array containing the values [2, 3, 4]. It will do this by calling the function inc with each element of the array.
Now, if you use this method a lot, you might continuously be calling map with all sorts of arguments:
arr.map(inc); // to increase each element
arr.map(even); // to create a list of booleans (even or odd)
arr.map(toString); // to create a list of strings
If for some reason you'd want to replace the entire array with the same string (but keeping the array of the same size), you could call it like so:
arr.map(this.String.Get("my String"));
This will create a new array of the same size as arr, but just containing the string "my String" over and over again.
Note that in some languages, this function is predefined and called const or constant (since it will always return the same value, each time you call it, no matter what its arguments are).
Now, if you think that this example isn't very useful, I would agree with you. But there are cases, when programming with higher order functions, when this technique is used.
For example, it can be useful if you have a tree you want to 'clear' of its values but keep the structure of the tree. You could do tree.map(this.String.Get("default value")) and get a whole new tree is created that has the exact same shape as the original, but none of its values.
It assigns an object that has a property "Get" to this.String. "Get" is assigned an anonymous function, which will return a function that just returns the argument that was given to the first returning function. Sounds strange, but here is how it can be used:
var ten = this.String["Get"](10)();
ten will then contain a 10. Instead, you could have written the equivalent
var ten = this.String.Get(10)();
// saving the returned function can have more use:
var generatingFunction = this.String.Get("something");
alert(generatingFunction()); // displays "something"
That is, : just assigns some value to a property.
This answer may be a bit superflous since Tom's is a good answer but just to boil it down and be complete:-
this.String = {};
Adds an object to the current object with the property name of String.
var fn = function(val) {
return function() { return(val); }
}
Returns a function from a closure which in turn returns the parameter used in creating the closure. Hence:-
var fnInner = fn("Hello World!");
alert(fnInner()); // Displays Hello World!
In combination then:-
this.String = { Get: function(val) {
return function() { return(val); }
}
Adds an object to the current object with the property name of String that has a method called Get that returns a function from a closure which in turn returns the parameter used in creating the closure.
var fnInner = this.String.Get("Yasso!");
alert(fnInner()); //displays Yasso!