问题
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!
回答1:
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;
}
回答2:
I wrote a function that generates a chain whose valueOf
function and context (the this
) is continually updated with the new sum, no matter how many arguments are passed each time.
/* add function */
function add() {
"use strict";
var args, sum, chain;
args = Array.prototype.slice.call(arguments);
sum = typeof this === 'number' ? this : 0;
sum += args.reduce(function (p, n) { return p + n; }, 0);
chain = add.bind(sum);
chain.valueOf = function () {
return sum;
};
return chain;
}
/* 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 */
var add7 = add(7);
console.log('var 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 next call in the chain cannot access the binded function's custom valueOf
, and any script attempting to evaluate the function as a number cannot access its context.
The only downside is the requirement of strict mode
in order for this
to remain a primitive.
Here's an edit to support both strict mode
and non-strict mode:
function add() {
var args, sum, chain;
args = Array.prototype.slice.call(arguments);
// Number object from non-strict mode
if (this instanceof Number) {
sum = Number(this);
// number primitive from strict mode
} else if (typeof this === 'number') {
sum = this;
// initial call to add
} else {
sum = 0;
}
sum += args.reduce(function (p, n) { return p + n; }, 0);
chain = add.bind(sum);
chain.valueOf = function () {
return sum;
};
return chain;
}
回答3:
function add(num1, num2){
if (num1 && num2) {
return num1 + num2;
} else if (num1) {
return function(num2){return num1 + num2;};
}
return 0;
}
回答4:
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
回答5:
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));
回答6:
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);
回答7:
I decided to add another solution for fun, using some ES6 features:
/* add function */
const add = (function add () {
const sum = [this, ...arguments].reduce((a, b) => a + b)
const chain = add.bind(sum)
chain[Symbol.toPrimitive] = hint => 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 */
var add7 = add(7)
console.log('var add7 = add(7)')
console.log(`add7(3) = ${add7(3)}`)
console.log(`add7(8) = ${add7(8)}`)
来源:https://stackoverflow.com/questions/31306312/javascript-function-challenge-add1-2-and-add12-both-should-return-3