This question already has answers here:
Pass an extra argument to a callback function
(5 answers)
Closed 6 years ago.
I have a question which has bugged me for a while now.
Let's say I have the following array:
var array = [1, 2, 3]
Now I have a function similar to this:
function print(num, str) {
console.log(str + ": " + num);
}
Is it possible to call the forEach method and pass a string to it?
// how do I pass "str"?
array.forEach(print);
Thanks!
You have two options here:
Either you swap the arguments, so that str comes first. Then you can use function.bind to bind the first arguments of the function:
function print(str, num) {
console.log(str + ": " + num);
}
array.forEach(print.bind(null, 'someStr'));
Alternatively, you can also create a new (anonymous) function which simply passes some value to the second argument:
array.forEach(function (item) { print(item, 'someStr'); });
With ES6 and the arrow functions, this even gets a bit prettier:
array.forEach(item => print(item, 'someStr'));
Both solutions have a very similar effect in that they create a new function object which is then passed to forEach. What makes more sense to you depends on your use cases.
And just as a note: You just need to remember that the callback passed to forEach actually takes up to three arguments (the item, the item’s index, and the array itself), so be careful when you pass a function that accepts other additional arguments. You can again use a local function to remedy that.
Not in this particular situation. The simple solution here is to use an anonymous function wrapper:
array.forEach(function (i) { print(i, str); });
If you reversed the parameters to print, you could do this a little more elegantly like so:
function print(str, num) { .. };
array.forEach(print.bind(null, str));
str will be bound as the first parameter, any parameters that forEach passes when invoking the callback are passed in second, third etc. place.
Here you go
var array = [1, 2, 3];
function print(str, num) {
console.log(str + ": " + num);
}
var str = 'someString';
array.forEach(print.bind(null, str));
Related
I'm working on a Javascript challenge. The challenge is the code below in which you add the numbers provided together:
function addTogether() {
//I left this blank because I'm focused on checking for the second parentheses
}
However, if you tried to pass this addTogether(5)(7) to the function addTogether(), it would be difficult to get the second parentheses.
However, you can get both parentheses if you write this code:
function addTogether() {
//get first parenteses
let first = arguments;
//get second parentheses
let second = function() {
return arguments;
};
}
But my question is how do you check if there's a second parentheses? Because I'm passing other data such as addTogether(2,3). In other words, I might be passing some with one parentheses and another with two parentheses to the function addTogether()
There is no way to check, unless you're parsing the source code, but your function can optionally accept second argument and if it's provided return the sum, otherwise return a function
const addTogether = (a, opt) => opt ? a + opt : b => a + b
console.log("addTogether(1,3) => ", addTogether(1,3))
console.log("addTogether(4)(6) => ", addTogether(4)(6))
Naive implementation using function that coerces to number.
Using reduce to calculate sums. Overriding ##toPrimitive to create function that coerces to value of add. Recursive call to generate recursively chainable callable number coercable functions.
Check ECMAScript specs if you want to customize behavior further. You will need to understand the conversion path.
function sum(...args) {
const first = args.reduce((sum,x)=>sum+x,0)
const second = function(...args) {return sum(first, ...args)}
second[Symbol.toPrimitive] = function(){return first}
return second
}
console.log(
1+sum(1)(2)+sum(1)+sum(3),
sum(1,1,2) (1,3)(0)(0)+sum(0,-1,1,0),
sum(1)(1)(2)(1)(3)(0)(0)(-1,1)(0)+sum()
)
This question already has answers here:
What is the order of evaluation for function arguments in Javascript?
(3 answers)
Closed 5 years ago.
say I have this:
function write3(a, b, c) {
document.write(a + " " + b + " " + c);
}
var arr = [1, 2, 3];
var i = 0;
write3(arr[i++], arr[i++], arr[i++]);
It results in 1 2 3 as expected, however, I'm not sure that this is guaranteed behavior. Could the arguments passed to write3 hypothetically be resolved in any other order than left to right?
Yes, the order of argument evaluation is guaranteed to be left-to-right.
According to sections 11.2.3 and 11.2.4 of the ES5 spec, function arguments are Argument Lists, and Argument Lists should always be evaluated left to right.
Specifically, the function to call gets evaluated, and then the function's arguments are evaluated from left to right.
Could the arguments passed to write3 hypothetically be resolved in any other order than left to right?
No, they will always be resolved left-to-right. This is guaranteed behavior.
I also feel like I should point out that you can call a function with an array of arguments using apply:
write3.apply(null, arr)
. . . or the spread operator in ES6+ (may not be supported in all browsers):
write3(...arr)
Demo Snippet:
function write3(a, b, c) {
document.write(a + " " + b + " " + c)
}
var arr = [1, 2, 3]
write3.apply(null, arr)
write3(...arr)
Afterwords. If you use ES6 you can write:
write3(...arr)
This question already has answers here:
Pass an extra argument to a callback function
(5 answers)
Closed 6 years ago.
I have an array and now I want to execute a function on every element in the array.
I'm trying to use map() function. The question is, my callback function passed to map() has its own parameters (not element, index, array).
Can I pass parameters to such a callback function? How?
I can think of 2 different ways:
Using thisArg to set an options object as the this value in the callback:
var numbers = [1,2,3,4,5,6,7,8,9,10];
function callback(element) {
return element + this.add;
};
var mapped = numbers.map(callback, {
add: 10
});
console.log(mapped);
Using .bind() to set some arguments:
var numbers = [1,2,3,4,5,6,7,8,9,10];
function callback(add, element) {
return element + add;
};
var mapped = numbers.map(callback.bind(null, 10));
console.log(mapped);
I think you might need to wrap your original function in another callback function, like this:
var array = ['one', 'two', 'skip-a-few', 'three', 'four']
console.log(
array.map(function (element) {
return original('other', 'variables', element)
})
)
// this function doesn't matter, just an example
function original(a, b, c) {
return a + ' ' + b + ' ' + c
}
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.
is it possible to pass multiple arguments using a single variable? For example, if I wanted to do something like:
function foo(x,y){
document.write("X is " + x);
document.write("Y is " + y);
}
var bar = "0,10";
foo(bar);
The example above is an simplified example of what I was trying to do. It doesn't work (because the "bar" is detected as a single argument). I know that there are easier ways to implement this using arrays.
So, I ask this question mostly out of curiosity - is it possible to get the "bar" variable to be detected as not one, but 2 arguments?
Thanks!
function foo(thing) {
document.write("X is " + thing.x);
document.write("Y is " + thing.y);
}
var bar = {x:0, y:10};
foo(bar);
What you're asking for is impossible. If you want to pass multiple values in a single argument, use an Array or an Object. If you really must use a string, you'll have to call split() to break the argument string into an array.
function Add (a, b, c) {
return a + b + c;
}
var nums = [1, 2, 4];
var sum = Add.apply (null, nums);
variable-length argument list:
function Add () {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
var n = Add (1, 2, 3, 4, 5);
Reference: apply method (Function object)
Sure, this is common to pass an object for options
function foo(options){
//...
}
then you can pass in anything...
var opts = {};//create an object
opts['x'] = 5;//set whatever properties you want
opts['y'] = 23;
opts['border'] = 3;
foo(opts);//pass 1 argument, with as many values as you want
Often these are defined inline, especially if the values are not needed outside of the method call.
foo({'x':5,'y':23,'border':3});
Not really.
You could do:
window.foo.apply(window, bar.split(','));
(Apply lets you pass an array of arguments instead of each argument separately)
… but the phrase "ugly" comes to mind.
You may use this:
var bar = [0,10]; // creates an array
foo(bar);
function foo(arg){
document.write("X is " + arg[0]);
document.write("Y is " + arg[1]);
}
No, but you could pass a an array or object:
function foo(options){
document.write("X is " + options.x);
document.write("Y is " + options.y);
}
var bar = {x: 0, y:10};
No, it's not possible. You could put two arguments in an array, but an array is still one variable. Then you would need to rewrite the function to accept one variable, and treat it as an array, like this:
function foo(x){
document.write("X is " + x[0]);
document.write("Y is " + x[1]);
}
Basically, a function accepts variables as arguments and, no matter what kind of variable you pass it, each variable is still only one variable - there's no way to get a single variable to be recognized as multiple arguments. An array is one variable, a JSON object is one variable, etc. These things have multiple parts to them, but they're encapsulated by a single variable.
How about? (For ES6+)
function foo({x, y}){
document.write("X is " + x);
document.write("Y is " + y);
}
and call it with:
foo({x:10, y:5})
There is a downside to using a single structured argument over multiple arguments, and that is with multiple arguments you can use /** in may IDEs to generate a method header which will display an #param for each argument.
But if you only have one argument then you will lose the niceness of a description for each argument and hence less useful intelli-sense in the IDE as it wont pick up the docuemntation of the structure's properties.
/**
* Do stuff
* #param {*} param0 - A structure containing the blah, blah blah data
*/
function foo({x, y}){
instead of..
/**
*
* #param {*} x - The value for blah
* #param {*} y - the value for blah-blah
*/
foo1(x, y){
To directly answer your question, no. It's worth noting that the way you have bar defined it's only one value, a string containing "0,10".
function myFunction(a,b){
//do stuff with a and b here
}
myFunction(1,'text')
or...
<a onClick="myFunction(1,'text');"
There's an article on the issue here.