Could any one explain how this function alert, when more no of brackets of parameters are passed. I could not able to understand it clearly.
function sum(a) {
It doesn't work as intended in all of the cases... The problem is that .toString
is expected to return a string, so string methods in provided implementation, would not work, e. g. sum(2)(3).split()
will cause an error.
Although we might assume sum()
result will always be expected to be a number, it might not be true in some cases and might be hard to debug, e. g. I noticed the issue when I was testing code initially written with .toString
only on jsbin.com (it does split
on console.log argument internally, overriding it).
Instead, .toString
should look like return String(result);
. Good thing that .toString
(when there's no .valueOf
or modern Symbol.toPrimitive
) will handle primitives conversion, so code expecting a Number will work as well. The possible issue here might be "double" conversion caused by this.
Better solution might be to use either pair of .toString
and .valueOf
or just a single Symbol.toPrimitive
if you're only targeting modern browsers.
Example using Symbol.toPrimitive
:
function sum(a) {
let result = a;
function f(b) {
result += b;
return f;
}
f[Symbol.toPrimitive] = hint => hint === 'string' ? String(result) : result;
return f;
}
Example using .toString
and .valueOf
pair.
function sum(a) {
var result = a;
function f(b) {
result += b;
return f;
}
// avoiding double conversion which will happen in case of .toString
f.valueOf = function() { return result; };
f.toString = function() { return String(result); };
return f;
}
alert
expects a string. If it doesn't get a string, it will attempt to convert whatever object it receives (and a function is a type of object) into one. If the object has a toString
method, then that will be called to perform said conversion.
The thing to look at is this piece of code
function f(b) {
sum += b
return f
}
This function returns reference to itself so it can be called as many times as possible. An important thing about it is that it has a tostring function that gets called and since tostring is defined inside function sum()
it has access to the variable sum
and its value current value (that is changed by f()
)
The first time your function is called, the first value is stored in sum
. After that function f(b)
will be returned, maintaining the provisional result in sum
. With each consecutive call you execute function f
- you perform sum += b
and return f again. If a string context is required (such as in the alert
, or a console.log
) f.toString
is called instead, returning the result (sum
).
function sum(a) {
var sum = a
function f(b) {
sum += b
return f //<- from second call, f is returned each time
// so you can chain those calls indefinitely
// function sum basically got "overridden" by f
}
f.toString = function() { return sum }
return f //<- after first call, f is returned
}
Explanation:
alert( sum(6)(-1)(-2)(-3) ) // 0
/\ function sum called, f returned
/\ the returned function f is called, f returns itself
/\ again
/\ and again
/\ at last, alert() requires string context,
so f.toString is getting invoked now instead of f
The sum
and f
functions always return the f
function, you can invoke it infinite times without getting a result other than the function.
The value is only returned by the overwritten toString
method of f
(which actually returns a number):
console.log( sum(1)(2) ) // Function(){}
console.log( sum(1)(2).toString() ) // 3
The alert
function implicitly invokes the toString
method when it casts its arguments to strings.