I have two functions:
function g(data, i){}
function f(data, i){}
I want to call them like:
var myVar = f(g(data, i));
So g() should return (data, i).
Of course, it doesn't work. Is there some way to do this?
Returning multiple values is not supported by Javascript (at least not in the implementations that most browsers have).
Do the following:
function g(data, i) {
// some code
return {
data: data,
i: i
};
}
var o = g(data, i);
f(o.data, o.i);
Note:
As mentioned by Phil in the Question's comments, if i is not modified in g(), then you can just call f(g(data, i), i) without modifying function g.
there is, if you use apply and make your functions return arrays of values.
function g(a, b) { return [a, b]; }
function f(c, d) { return [c, d]; }
console.log(f.apply(null, g("thing", "cow")));
This is, however, a great sign of a bad programmer if used for this purpose, so you don't want to do this. If you have functions that take two arguments, pass two arguments:
function g(a, b) { return [a, b]; }
function f(c, d) { return [c, d]; }
var result = g("thing", "cow");
f(result[0], result[1]);
because you already know it takes, and generates, a pair of values, or use the object pattern (rather than an array) that Der Flatulator shows you.
Not exactly like you have it, however you can trick it since arguments is "array-like" ... behold :D
var g = function(a,b) {return [a,b]};
var f = function(a, b) {console.log("f evaluating", a, b)};
f.apply(null,g(1,2));
gives you:
bar 1 2
Alternatively you could do something hacky in your (f) function to split the values of the first argument if there is only one argument passed in, but I like the apply better, especially cuz this is horrible if for example your a argument is an array by itself.
Works for any number of argument length
function g(){
return [].slice.call(arguments);
}
function f(data, i){
}
f.apply(undefined, g(data, i));
Related
In a recent interview, I was asked to write a function that adds numbers and accepts parameters like this:
add(1)(2)(3) // result is 6
add(1,2)(3,4)(5) // result is 15
The number of parameters is not fixed, and the arguments can be either passed in sets or individually.
How can I implement this add function?
Given your examples, the number of parameters is fixed in some ways.
As #ASDFGerte pointed out, your examples seem to return the result after three invocations. In this case a simple implementation without introducing terms like variadic and currying could be
function add(...args1){
return function(...args2){
return function(...args3){
return args1.concat(args2).concat(args3).reduce((a,b)=>a+b)}}}
console.log(add(1)(2)(3))
console.log(add(1,2)(3,4)(5))
Every invocation accepts a variable number of parameters.
However it would be nice to generalize the construction of this nested functions structure and you can accomplish that with currying.
But if you want to allow an arbitrary number of invocations, when you should stop returning a new function and return the result? There is no way to know, and this is a simple, unaccurate and partial explanation to give you the idea of why they said you cannot accomplish what they asked you.
So the ultimate question is: is it possible that you misunderstood the question? Or maybe it was just a trick to test you
Edit
Another option would be to actually invoke the function when no arguments are passed in, change the call to add(1)(2)(3)()
Here an example recursive implementation
function sum (...args) {
let s = args.reduce((a,b)=>a+b)
return function (...x) {
return x.length == 0 ? s : sum(s, ...x)
};
}
console.log(sum(1,2)(2,3,4)(2)())
At every invocation computes the sum of current parameters and then return a new function that:
if is invoked without parameters just return the current sum
if other numbers are passed in, invokes recursively sum passing the actual sum and the new numbers
I'm a bit late to the party, but something like this would work (a bit hacky though in my opinion):
const add = (a, ...restA) => {
const fn = (b, ...restB) => {
return add([a, ...restA].reduce((x, y) => x + y) + [b, ...restB].reduce((x, y) => x + y))
};
fn.valueOf = () => {
return [a, ...restA].reduce((x, y) => x + y)
};
return fn;
}
This function returns a function with a value of the sum. The tests below are outputing the coerced values instead of the actual functions.
console.log(+add(1,2)(3,4)(5)); // 15
console.log(+add(1)) // 1
console.log(+add(1)(2)) // 3
console.log(+add(1)(2)(3)) // 6
console.log(+add(1)(2)(3)(4)) // 10
Since it's a currying function, it will always return another function so you can do something like this:
const addTwo = add(2);
console.log(+addTwo(5)); // 7
using reduce and spread it can be done as below
function calc(...args1){
return function (...args2){
return function (...args3){
let merge = [...args1, ...args2, ...args3]
return merge.reduce((x ,y)=> x + y) ;
}
}
}
let sum = calc(10)(1)(4);
console.log("sum",sum);
They probably wanted to know how comfortable you were with "javascript internals", such as how and when methods like Function#toString and Function#valueOf, Function#[Symbol.toPrimitive] are called under the hood.
const add = (...numbers) => {
const cadd = (...args) => add(...args, ...numbers);
cadd[Symbol.toPrimitive] = () => numbers.reduce((a, b) => a + b);
return cadd;
}
console.log(
`add(1,2)(3,4)(5) =>`, add(1,2)(3,4)(5),
); // result is 15
console.log(
`add(1,2) =>`, add(1,2),
); // result is 3
console.log(
`add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5) =>`, add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5),
); // result is 32
I have code that is using currying to get the average on an array that results from concatenating two arrays: an n size array and an m size array.
var avg = function(...n){
let tot=0;
for(let i=0; i<n.length; i++){
tot += n[i];
}
return tot/n.length;
};
var spiceUp = function(fn, ...n){
return function(...m){
return fn.apply(this, n.concat(m));
}
};
var doAvg = spiceUp(avg, 1,2,3);
console.log(doAvg(4,5,6));
In this line return fn.apply(this, n.concat(m));, I don't understand why do we need to use apply. What is the object we are binding with the average function and why does just normal calling (return fn(n.concat(m));) not work?
In that example, this is not that important. It would also work if instead of this you would pass an empty object instead. It's just an example on how to use apply.
What you need to focus is on the second parameter n.concat(m). They key concept here is that passing an array as a second argument you are calling that function (fn) passing each value in the array as an argument.
About your second question: no, it won't work because fn expects several arguments (one per value to calculate the average) while by doing return fn(n.concat(m)); you are just passing one argument, an array containing all values
Maybe you would understand it better with a simpler example:
function sum3params(a,b,c){
return a+b+c;
}
console.log(sum3params([3,4,2])) // won't work
console.log(sum3params.apply(this, [3,4,2])) // will work ('this' is not important here)
For this use case, it does not. But consider the following:
var foo = {
bar: 3
};
var addBar = function(a, b) { return a + b + this.bar };
foo.add3AndBar = spiceUp(addBar, 3);
foo.add3AndBar(1); // 7
Using apply means that your spiceUp function can be applied to methods as well as normal functions. For more likely example, consider partially applying when defining a method on a prototype:
const ENV = "linux";
DoesSomePlatformSpecificStuff.prototype.getPath = spiceUp(ENV);
apply also will spread the gathered array of arguments back out into positional arguments which can also be done like so:
return fn(...n.concat(m));
Which can be simplified as
return fn(...n, ...m);
Which is equivalent to
return fn.apply(undefined, n.concat(m));
while I was going through concepts related to JavaScript functions, I came up with problem which I'm unable to figure it out. I use following codes i.e one with return as a function and the other as a simple function as follows
function plus(a, b) {
return(
console.log(a+b),
console.log(this),
console.log(arguments)
)
}
plus(4,5);
and
function plus(a, b) {
console.log(a+b),
console.log(this),
console.log(arguments)
}
plus(4,5)
But when I run both I'm not able to figure it out since both results same in console. So I just want to know when should I use return as function.? and what is its main purpose? I've seen answers here but those related to return entire function or objects but didn't find specific answer to return as a function. So please help me in it.
return(
console.log(a+b),
console.log(this),
console.log(arguments)
)
statement means:
return the argument that is represented by (...) expression. Here parentheses is not a part of a return keyword syntax, but is a standalone operator used in conjunction with operator ,.
The (1, 2, 3) expression after evaluating returns the value of the last expression.
In your case it's console.log(arguments) which returns undefined.
References:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
This
function plus(a, b) {
return(
console.log(a+b),
console.log(this),
console.log(arguments)
)
}
is an equivalent of this:
function plus(a, b) {
var r = (
console.log(a+b),
console.log(this),
console.log(arguments)
);
return r;
}
or simply this (EDIT, but is wrong, see zerkms comment ):
function plus(a, b) {
var r =
console.log(a+b),
console.log(this),
console.log(arguments);
return r;
}
where ,, is an expression - compute all parts delimited by commas with result of last expression.
Is there way to get my own custom function in a chain of lodash. So for example like this:
var l = [1,2,3]
var add = function(a, b){return a+b}
var r =_.chain(l).find(function(a){return a>1}).add(5).value()
=>r = 7
What you look for is a way to extend the lodash prototype. It so nicely turns out that you can do it easily with a mixin utility function. Check here the docs:
http://lodash.com/docs#mixin
In your example it will look like:
var l = [1,2,3];
var add = function(a, b){return a+b}
_.mixin({
add: add
});
var r =_.chain(l).find(function(a){return a>1}).add(5).value()
console.log(r); ==> 7
and here is live sample on fiddle: http://jsfiddle.net/g2A9C/
After #stride anwswer I came up with a more generic solution using _.mixin:
function add(a, b, c) {
return a + b + c
}
function sub(a, b, c) {
return a - b - c
}
_.mixin({
run: function (v, f) {
var args = Array.prototype.slice.call(arguments, 2)
args.unshift(v)
return f.apply(this, args)
}
})
var r = _.chain(1).run(add, 1, 1).run(sub, 2, 2).value()
console.log(r) -> -1
1 + 1 + 1 - 2 - 2 = -1
http://jsbin.com/iyEhaMa/1/
After all I wonder why this not a build in function in lodash.
Another option is to just drop chaining and leverage function composition through _.flow.
From the DOCS:
[Flow] Creates a function that returns the result of invoking the given
functions with the this binding of the created function, where each
successive invocation is supplied the return value of the previous.
This means that every function inside Flow will receive as input the output of the previous one. In practice this means we are not limited to using only Lodash API methods, but we can mix and match whatever function we fancy, as long as the next one is able to handle that return value.
var l = [1,2,3]
var add = _.curry((a, b) => a + b);
_.flow(
_.find(a => a > 1),
add(5),
)(l);
// => 7
NB - This example is using the Functional version of Lodash, if you don't want or can't use that one you can still achieve the same result, check my other answer to another question about Lodash.
Maybe it's too late but _.tap is another chance
Is it possible to get all of the arguments a Javascript function is written to accept? (I know that all Javascript function arguments are "optional")? If not, is it possible to get the number of arguments? For example, in PHP, one could use:
$class = new ReflectionClass('classNameHere');
$methods = $class->getMethods();
foreach ($methods as $method) {
print_r($method->getParameters());
}
... or something like that, I haven't touched PHP in a while so the example above may not be correct.
Thanks in advance!
EDIT: Unfortunately, I have to be able to get the arguments outside of the body of the function... Sorry for the lack of clarification, but thanks for the current answers!
This new version handles fat arrow functions as well...
args = f => f.toString ().replace (/[\r\n\s]+/g, ' ').
match (/(?:function\s*\w*)?\s*(?:\((.*?)\)|([^\s]+))/).
slice (1,3).
join ('').
split (/\s*,\s*/);
function ftest (a,
b,
c) { }
let aftest = (a,
b,
c) => a + b / c;
console.log ( args (ftest), // = ["a", "b", "c"]
args (aftest), // = ["a", "b", "c"]
args (args) // = ["f"]
);
Here is what I think you are looking for :
function ftest (a,
b,
c) { }
var args = ftest.toString ().
replace (/[\r\n\s]+/g, ' ').
match (/function\s*\w*\s*\((.*?)\)/)[1].split (/\s*,\s*/);
args will be an array of the names of the arguments of test i.e. ['a', 'b', 'c']
The value is args will be an array of the parameter names if the ftest is a function.
The array will be empty if ftest has not parameters. The value of args will be null
if ftest fails the regular expression match, i.e it is not a function.
it is possible get all the formal parameter name of a javascript:
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
function formalParameterList(fn) {
var fnText,argDecl;
var args=[];
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
var r = argDecl[1].split(FN_ARG_SPLIT);
for(var a in r){
var arg = r[a];
arg.replace(FN_ARG, function(all, underscore, name){
args.push(name);
});
}
return args;
}
this can be tested this way :
var expect = require('expect.js');
expect( formalParameterList(function() {} )).to.eql([]);
expect( formalParameterList(function () {} )).to.eql([]);
expect( formalParameterList(function /* */ () {} )).to.eql([]);
expect( formalParameterList(function (/* */) {} )).to.eql([]);
expect( formalParameterList(function ( a, b, c ,d /* */, e) {} )).to.eql(['a','b','c','d','e']);
Note:
This technique is use with the $injector of AngularJs and implemented in the annotate function. (see https://github.com/angular/angular.js/blob/master/src/auto/injector.js and the corresponding unit test in https://github.com/angular/angular.js/blob/master/auto/injectorSpec.js )
Suppose your function name is foo
Is it possible to get all of the arguments a Javascript function is
written to accept?
arguments[0] to arguments[foo.length-1]
If not, is it possible to get the number of arguments?
foo.length would work
check only required chars. with func.toString().regex you checked full length.so if function is class with 500 lines of code...
function getParams(func){
var str=func.toString();
var len = str.indexOf("(");
return str.substr(len+1,str.indexOf(")")-len -1).replace(/ /g,"").split(',')
}
HBP's answer is what most people are looking for, but if you're the one defining the function, you can also assign a property to the function object. For example,
a.arguments = ['foo', 'bar', 'baz']
function a(foo, bar, baz) {
// do stuff
}
This is debatably more clear, but you'll have to write your arguments twice.
Now when you say outside the body of the function I can only imagine that you want to know what the names of the parameters are? Because as far as the values go, you already know what arguments you are passing. Other answers have said you can get the length of the function, which is the number of parameters it explicitly declares. Now if you want to know the names outside the function, how about the toString hack?
Consider
function f(oh, hi, there) {
return hi + there / oh;
}
Then
alert(f);
What do you see? RIght, just regex them out! Okay, SORRY to bring this up. Perhaps it is not standard ECMAScript, but it, uh, works in Chrome....
args = f => f.toString ()
.replace( /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,'')
.replace(/(\r\n\t|\n|\r\t)/gm,"")
.trim()
.match (/(?:\w*?\s?function\*?\s?\*?\s*\w*)?\s*(?:\((.*?)\)|([^\s]+))/)
.slice (1,3)
.join ('').replace(/\s/g, '').
split (/\s*,\s*/);
/*Test*/
console.log(args((a,b)=>a+b));
console.log(args(function(c,d){return c+d;}));
console.log(args(async function(a,b,c){/**/}));
console.log(args(function* (a,b,c,d){/**/}));
console.log(args(function name(s1,s2){}));
console.log(args(function name(/*comment 1*/ s3/*comment2*/,s4//
){}));
console.log(args(async function* name(/*comment1*/ s5/*comment2*/,s6){}));
console.log(args(async function * name(/*comment1*/ s7/*comment2*/,s8){}));
console.log(args(async function *name(/*comment1*/ s9/*comment2*/,s10){}));
JavaScript is a dialects of ECMAScript, according to ECMAScript standard, a function is also a object, and when a function is called, function can access arguments object, this arguments is array-like object, it has length property, so you can use arguments.length to traverse all arguments passed to this function.
visit http://interglacial.com/javascript_spec/a-13.html#a-13.2.1 for more details.