A friend of mine challenged me to write a function that works with both of these scenarios
add(2,4) // 6
add(2)(4) // 6
My instinct was the write an add() function that returns itself but I'm not sure I'm heading in the right direction. This failed.
function add(num1, num2){
if (num1 && num2){
return num1 + num2;
} else {
return this;
}
}
alert(add(1)(2));
So I started reading up on functions that return other functions or return themselves.
http://davidwalsh.name/javascript-functions
JavaScript: self-calling function returns a closure. What is it for?
JavaScript: self-calling function returns a closure. What is it for?
I am going to keep trying, but if someone out there has a slick solution, I'd love to see it!
I wrote a curried function whose valueOf() method and function context (this) are bound with the sum no matter how many arguments are passed each time.
/* add function */
let add = function add(...args) {
const sum = args.reduce((acc, val) => acc + val, this);
const chain = add.bind(sum);
chain.valueOf = () => sum;
return chain;
}.bind(0);
/* tests */
console.log('add(1, 2) = ' + add(1, 2));
console.log('add(1)(2) = ' + add(1)(2));
/* even cooler stuff */
console.log('add(1, 2)(3) = ' + add(1, 2)(3));
console.log('add(1, 2, 3)(4, 5)(6) = ' + add(1, 2, 3)(4, 5)(6));
/* retains expected state */
let add7 = add(7);
console.log('let add7 = add(7)');
console.log('add7(3) = ' + add7(3));
console.log('add7(8) = ' + add7(8));
The reason why both mechanisms are required is because the body of add() must use the called function's bound context in order to access the sum of the intermediate partial application, and the call site must use the valueOf() member (either implicitly or explicitly) in order to access the final sum.
There is an article on Dr.Dobs Journal about "Currying and Partial Functions in JavaScript" which describes exactly this problem.
One solution found in this article is:
// a curried add
// accepts partial list of arguments
function add(x, y) {
if (typeof y === "undefined") { // partial
return function (y) {
return x + y;
};
}
// full application
return x + y;
}
function add(num1, num2){
if (num1 && num2) {
return num1 + num2;
} else if (num1) {
return function(num2){return num1 + num2;};
}
return 0;
}
The concept that you're looking for is called currying and it has to do with function transformation and partial function application. This is useful for when you find yourself calling the same function over and over with mostly the same arguments.
An example of implementing add(2)(6) via currying would look something like this...
function add(x,y) {
if (typeof y === 'undefined') {
return function(y) {
return x + y;
}
}
}
add(2)(4); // => 6
Additionally, you could do something like this...
var add6 = add(6);
typeof add6; // => 'function'
add6(4); // => 10
var add = function(){
// the function was called with 2 arguments
if(arguments.length > 1)
arguments.callee.first_argument = arguments[0];
// if the first argument was initialized
if(arguments.callee.first_argument){
var result = arguments.callee.first_argument + arguments[arguments.length - 1];
arguments.callee.first_argument = 0;
return result;
}else{// if the function was called with one argument only then we need to memorize it and return the same function handler
arguments.callee.first_argument = arguments.callee.first_argument || arguments[0];
return arguments.callee;
}
}
console.log(add(2)(4));
console.log(add(2, 4));
An extended solution which depends on the environment:
function add(){
add.toString = function(){
var answer = 0;
for(i = 0; i < add.params.length; i++)
answer += add.params[i];
return answer;
};
add.params = add.params || [];
for(var i = 0; i < arguments.length; i++)
add.params.push(arguments[i])
return add;
}
console.log(add(2)(4)(6)(8))
console.log(add(2, 4, 6, 8));
We can use the concept of closures which is provided by Javascript.
Code snippet:
function add(a,b){
if(b !== undefined){
console.log(a + b);
return;
}
return function(b){
console.log(a + b);
}
}
add(2,3);
add(2)(3);
In general you need to have an agreement whether the function should return a function (for calling with more arguments) or the end result. Imagine the add function would have to work like this as well:
add(1, 2, 3)(4, 5) // -> 15
...then it becomes ambiguous, because you might want to call again:
add(1, 2, 3)(4, 5)(6) // -> 21
...and so add(1, 2, 3)(4, 5) should have returned a function, and not 15.
You could for instance agree that you have to call the function again, but without arguments, in order to get the numeric result:
function add(...args) {
if (args.length === 0) return 0;
let sum = args.reduce((a, b) => a+b, 0);
return (...args) => args.length ? add(sum, ...args) : sum;
}
console.log(add()); // 0
console.log(add(1,2,3)()); // 6
console.log(add(1,2,3)(4,5)()); // 15
console.log(add(1,2,3)(4,5)(6)()); // 21
One may think that he/she has to invoke the same function two times, but if you think deeply you will realize that the problem is pretty straight forward, you have to invoke the add function one time then you need to invoke what ever the add function returns.
function add(a){
return function(b){
return a+b;
}
}
console.log(add(20)(20));
//output: 40
you can return function as many as time you want. suppose for y = mx+c
const y= function (m){
return function(x){
return function (c){
return m*x+c
}
}
}
console.log(y(10)(5)(10));
//out put: 60
I am new to node js and taking a course to learn it. However, I am not able to make a simple closure property of javascript work in it. I have 2 files index.js and rectangle.js where in I am using callback to return the area & perimeter of rectangle.
index.js
var rect = require('./rectangle');
function solveRect(l,b) {
console.log("Solving for rectangle with l = " + l + "and b = " + b);
rect(l,b, (err,rectangle) => {
if(err) {
console.log("ERROR: " + err.message);
}
else {
console.log("The area of rectangle of dimensions l = "
+ l + "and b = " + b + " is " + rectangle.area());
console.log("The perimeter of rectangle of dimensions l = "
+ l + "and b = " + b + " is " + rectangle.perimeter());
}
});
console.log("This statement is after the call to rect()");
}
solveRect(2,4);
solveRect(3,5);
solveRect(0,4);
solveRect(-3,-5);
rectangle.js
module.exports = (x,y,callback) => {
if( x <= 0 || y <= 0) {
setTimeout(() =>
callback(new Error("rectangle dimensions should be greater than zero"),
null),
2000
);
}
else {
setTimeout(() =>
callback(null,
{
perimeter: (x,y) => (2*(x+y)),
area: (x,y) => (x*y)
}),
2000
);
}
}
I see that since length and breadth are already available to the callback from the outer scope, there isn't any need to pass them when we call the rectangle.area() function.
Output: I get NaN returned as area and perimeter and not the actual calculated area.
The perimiter and area functions take arguments x and y, so they use those arguments to calculate the results, not the variables inherited from the closure. Since you're not supplying any arguments when you call them in solveRect(), you're performing arithmetic on undefined, which results in NaN.
Get rid of the arguments so they'll use the closure variables.
setTimeout(() =>
callback(null,
{
perimeter: () => (2*(x+y)),
area: () => (x*y)
}),
2000
);
Function addOne returns undefined result...
const t = 5;
const b = 8;
function addOne () {
add (t + b);
return addOne;}
Pls help to get a sum of 5 + 8 with this function.
const t = 5;
const b = 8;
function addOne () {
return t+b;
}
console.log(addOne()); //13
I am not sure what you are asking, since your method's name is not matching with your implementation. But here are some code that might help you:
const t = 5;
const s = 8; // Note that I have renamed the parameter's name
function addOne () {
return s + 1;
}
function addOneToParameter(x) {
return x + 1;
}
function addTwoConstants () {
return t + s;
}
function addTwoParameters (a, b) {
return a + b;
}
console.log(addOne()); // 9 (The constant 's' + 1)
console.log(addTwoConstants()); // 13 (The constant 's' + constant 't')
console.log(addTwoParameters(1,2)); // 3 (The first parameter + the second parameter)
console.log(addOneToParameter(4)); // 5 (The parameter + 1)
In your original question, you don't need to use a function to perform an addition of two integers. In other words, simply use '+' as operand. Furthermore, pay attention how to return a value from your function.
This question already has answers here:
Official information on `arguments` in ES6 Arrow functions?
(2 answers)
Are 'Arrow Functions' and 'Functions' equivalent / interchangeable?
(4 answers)
Closed 5 years ago.
I have the following code
function coroutine(g) {
var it = g();
return () => it.next.apply(it, arguments);
// also tried () => { return it.next.apply(it, arguments);
}
var run = coroutine(function* () {
var x = 1 + (yield);
var y = 1 + (yield);
yield (x + y);
});
And the following testing has been executed.
run()
{value: undefined, done: false}
run(10)
{value: undefined, done: false}
run(30).value
"1function* () { var x = 1 + (yield); var y = 1 + (yield); yield (x + y);}1function* () { var x = 1 + (yield); var y = 1 + (yield); yield (x + y);}"
However, shouldn't the last run(30).value returns the value of 42?
However, it works after I change the arrow function to old anonymous function?
function coroutine(g) {
var it = g();
return function() { return it.next.apply(it, arguments) };
}
I'm trying to flip the parameters of a function passed to another function:
function dash(a,b) {
return a + " - " + b;
}
function flipArgs(fn) {
return fn;
}
flipArgs(dash)(1,2);
Currently it returns "1 - 2", I need to return "2 - 1". How can I access to the arguments passed to my "flipArgs" function?
You can do this :
function flipArgs(fn) {
return function(){
return fn(arguments[1], arguments[0]);
}
}
Of course, depending on your needs, you could use a larger swap, or test arguments.length.
#dystroy answer is great, but there is a more generic way, take a look:
function dash(a,b,c) {
return a + " - " + b + " - " + c;
}
function flipArgs(fn) {
return function(){
return fn.apply(this, Array.prototype.reverse.call(arguments));
}
}
var r = flipArgs(dash)(1,2,3);
console.log(r); // 3 - 2 - 1
JSFiddle: http://jsfiddle.net/u3f4t919/1/