I'm working on an open source project and stumbled over bitwise operators. I do understand the principles and also that javascript evaluates non-zero integer values to true (correct me here if I'm wrong; found this statement in an accepted answer in another post).
The code in question is as follows:
function example(){
var args = arguments;
var j = 1 & args[0];
.
.
.
}
var test = {keyA: 1, keyB: 2};
example(test);
My Question is: What's the value of j?
What is the binary equivalent of an object?
As far as i understand it, j = 0 if the last bit in test is 0 and j = 1if the last bit in testis 1.
Please help me out here guys. I spend the last hour searching any nearly related post here and most topics are about numbers, one or two were about booleans and that's that.
Edit:
As the code example given above doesn't seem to be as clear as i thought, here the full function as i found it (and working):
function Extend() {
var args = arguments;
var target;
var options;
var propName;
var propValue;
var deep = 1 & args[0];
var i = 1 + deep;
target = args[i - 1] || {};
for (; i < args.length; i++) {
// Only deal with non-null/undefined values
if (options = args[i]) {
// Extend the base object
for (propName in options) {
propValue = options[propName];
if (propValue !== undefined) {
propValue = options[propName];
target[propName] = (deep && IsPlainObject(target[propName])) ? Extend(deep, {}, propValue) : propValue;
}
}
}
}
// Return the modified object
return target;
}
var _someVariable = Extend({keyA: 1, keyB: 2, keyC: 10}, _someOtherVariable);
deephas to have some meaning as it determines whether to enter the FOR-loop ... or not.
The intent of the deep variable is to detect the difference between these two calls:
Extend({keyA: {a: 1}, keyB: 2}, {keyC: 3, keyA: {b: 2}});
and
Extend(true, {keyA: {a: 1}, keyB: 2}, {keyC: 3, keyA: {b: 2}});
The first variant will return this:
{keyA: {b: 2}, keyB: 2, keyC: 3}
The second is intended to return this:
{keyA: {a: 1, b: 2}, keyB: 2, keyC: 3}
So the function in fact allows for a first, optional argument, that will make the function apply the extension recursively so you get a deep instead of a shallow extended object.
You can also see this intent by analysing the recursive call, where the first argument is deep, the second is the object to extend, and the third the object to extend with.
The following line also shows this:
var i = 1 + deep;
As i is point where the loop will start from, you can see that if deep is set to 1 instead of 0, the loop will start processing from argument #2 onwards, which makes sense, as argument #0 was recognised as being the optional argument, and the next one is the target object.
Note that the function accepts a variable number of additional arguments which it will use to extend the target object with. It is over these arguments that the i variable loops.
As a side note: because of a bug, the second version returns the same as the first. To fix the bug, replace
target[propName] = (deep && IsPlainObject(target[propName]))
? Extend(deep, {}, propValue) : propValue;
with:
target[propName] = (deep && IsPlainObject(target[propName]))
? Extend(deep, target[propName], propValue) : propValue;
Now, coming to the essence:
var deep = 1 & args[0];
The use of the bitwise operator must have been an idea to have efficiency rule over clarity. The intent was to set deep to 1 if the first argument represented the optional argument, which should be a boolean indicating whether the extending should happen shallow or deep. As objects will make this expression evaluate to 0, it seemed like a nice trick.
But there is an issue with this. If one would like to do this:
Extend(["3"], {myattr: 2});
One would expect to get back an array-like object with an additional custom property myattr:
{0: "3", length: 1, myattr: 2}
However, the current Extend function will misinterpret the first argument as an instruction to perform a deep extension. This is because
1 & ["3"] will evaluate to 1 & 3, which evaluates to 1. And so the result will be the second argument without any extension happening:
{myattr: 2}
Conclusion: it is better to avoid such cryptic use of bitwise operators, and do something like this:
var deep = args.length > 0 && typeof args[0] === 'boolean' && args[0];
In common language: let deep be true (1) when there is at least one argument and that argument is a boolean and its value is true. In all other cases let it be false (0).
Note that one cannot pass false as the first argument, thinking that it will make the function perform a shallow extension. In this case,
that argument will be taken as the object to extend, which will fail. So the optional first argument, if provided, must be a boolean with value true.
This is true both for the original Extend function and the corrected one.
Finally, it would be good to add comments to this function to clarify the use of the first optional argument.
Bitwise operators do work on 32bit (un)signed integers. If you pass in anything that is not a number, it is implicitly coerced to a number. This is done using the valueOf/toString methods of the object as usual, and for your object {keyA: 1, keyB:2} will yield NaN. Then, this number is casted to an (U)int32, which gives 0 for NaN.
Check the spec for toUint32, follow it to ToNumber and on from there.
I have built an example using a couple of js classes for declaring Flag Enum and Flag Selections.
The source code is here in my github repo.
Basically to answer the question, and as mentioned by #Bergi, your class should implement valueOf() to return the value of the 'selections'.
// Example:
_w.Feature = new FlagEnum("Feature", {
CUSTOMER : "customer info" // 2
, ORDER : "order details" // 4
, DELIVERY : "delivery details" // 8
, DELIVERY_LIST : "listing of all deliveries" // 16
, DRIVER : "driver details" // 32
})
let [CUSTOMER, ORDER, DELIVERY, DELIVERY_LIST, DRIVER] = Feature.get_values()
features = new FlagSel(Feature, CUSTOMER | ORDER | DELIVERY)
// -or-
features = new FlagSel(Feature, [CUSTOMER, ORDER, DELIVERY])
// Using in code
// Check feature using bitwise mask:
if (features & ORDER){
pc("features includes ORDER")
}
// -or-
// Check feature using has method:
if (features.has(ORDER)){
pc("features includes ORDER")
}
// Managing values:
features.add(CUSTOMER)
features.rem(ORDER)
// Print available options
console.log(Feature)
// output: <FlagEnum - Feature> options: CUSTOMER, ORDER, DELIVERY, DELIVERY_LIST, DRIVER
// Print selected options
console.log(features)
// output: <FlagSel - Feature> CUSTOMER, ORDER, DELIVERY
Related
What is the best practice for me to sort an object of array by value of key that key is optional type from Object? I have following code that works if num is not optional type However, I got error that Object is possibly 'undefined'.
type Filter = {
a: number;
num?: number
}
const filter: Filter[] = [{a: 1, num: 10}, {a: 1, num: 12}, {a: 1, num: 5}]
filter.sort((a,b)=> (a.num > b.num ? 1 : -1))
console.log(filter)
2 options come to my mind:
The obvious one: use a type where num is not optional. You can use the Required utility type if you do not want to keep both types without rewriting the properties.
If you cannot change the type, that probably means you really want that property to be optional. So you simply should check for it in your sort function. You need to check if num is undefined and decide what to return when that occurs. When you check it, Typescript will infer everything that falls out of that condition will be defined.
For instance:
filter.sort((a,b)=> {
if (typeof a.num === 'undefined' || typeof b.num === 'undefined') {
return 0;
}
return (a.num > b.num ? 1 : -1)
})
To add to AqueleHugo's answer, I wanted to keep the field optional (to correctly reflect the 3rd party's interface), but still keep it clean, simple and readable, so I've gone with this and it works well for my situation:
interface WebPage {
// ...
order?: number;
}
const sortPages = (pages: WebPage[]): WebPage[] => {
return pages.filter(p => p.order).sort((p1, p2) => Number(p1.order) - Number(p2.order));
}
Hopefully someone else finds this useful!
TypeScript function chaining, but I want to programmatically chain them.
Example class: chain.ts
class MyChain {
value: number = 0;
constructor() {
this.value = 0;
}
sum(args: number[]) {
this.value = args.reduce((s, c) => s + c, 0);
return this;
}
add(v: number) {
this.value = this.value + v;
return this;
}
subtract(v: number) {
this.value = this.value - v;
return this;
}
}
const mc = new MyChain();
console.log(mc.sum([1, 2, 3, 4]).subtract(5).value);
I see the number 5 on the console.
Now, I'm still fairly new to JavaScript and TypeScript, so I figured out that the function within this class is actually an element of an array of the instance of the class. Hence, I can do this:
console.log(mc["sum"]([1, 2, 3, 4]).value);
This indeed returns the number 10.
Now, I'm confused as to how I'd chain this programmatically. For example (this is obviously not what I would want to do anyway and shows my boneheaded lack of understanding of JavaScript:
console.log(mc["sum"]([1, 2, 3, 4]).mc["subtract"](5).value);
Error:
Property 'mc' does not exist on type 'MyChain'.ts(2339)
Okay, in all honesty, I kind of intuitively knew that wasn't going to work. However, thinking about it, how would I go about accessing the elements of a multidimensional array in just about any reasonable language?
console.log(mc["sum"]([1, 2, 3, 4])["subtract"](5).value);
Bingo. This does the trick. But, this isn't really the solution I need. What I need is something like this:
interface IChainObject {
action: string;
operand: number | number[];
}
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4] },
{ action: "subtract", operand: 5 },
];
And, to start, I'd like to try this:
console.log(mc[chainObj[0].action](chainObj[0].operand).value);
And consequently, generating a mechanism that would ultimately build something like this:
console.log(
mc[chainObj[0].action](chainObj[0].operand)[chainObj[1].action](
chainObj[1].operand
).value
);
Hence, it seems to me that what I want is some way to generate this:
[chainObj[0].action](chainObj[0].operand)[chainObj[1].action](chainObj[1].operand)
from this, with my chain object having one or many action/operand object sets:
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4] },
{ action: "subtract", operand: 5 },
];
Now, this is where my brain more or less shuts down. I am thinking that I need to generate a chain of string values, but they'll just be strings and won't really work as array indexes into the function as I want.
Why do I want to do this? Ultimately, I want to build a complex Yup schema object from a JSON object. I found this excellent post, but my core issue is I don't really understand how this code works.
At this point, I am able to parse out the way Vijay was able to solve his issue and mimic it, in a way. Here's working code for my example:
const mc = new MyChain();
interface IChainObject {
action: string;
operand: number | number[];
}
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4, 5] },
{ action: "subtract", operand: 5 },
];
let myChain = {};
chainObj.forEach((o) => {
myChain = mc[o.action](o.operand);
});
console.log("myChain is", myChain["value"]);
Results in: myChain is 10
You're probably asking yourself, "What's your problem Dan?. You seem to have a solution in hand now." Yes, I guess I do, but I don't understand it. I'm basically copying and pasting code, marginally understanding it, and making changes that make it work.
My basic issue is I don't understand how this line of code works: myChain = mc[o.action](o.operand);
I get the general gist that it's calling the function based on the action and providing the data to the function via the operand. I'm a copy and paste code monkey. I want to be more than a monkey. Maybe a baboon or even ape. Hence, I want to understand what I've done. What doesn't make sense to me is how it's chaining it.
I thought maybe the secret was in the forEach function, but that doesn't seem to be it. Here is a simple test:
let p = 0;
const x = [1, 2, 3, 4];
x.forEach((y) => {
p = y;
});
console.log("p is", p); p is 4
What is the secret JavaScript magic that is happening under the hood that makes the myChain = mc[o.action](o.operand); code actually chain my functions together rather than simply work one and the work the other. I'm just not seeing it.
Let's start from the first misunderstanding I can find:
Now, I'm still fairly new to JavaScript and TypeScript, so I figured out that the function within this class is actually an element of an array of the instance of the class.
This is not the case. Square brackets in Javascript are used for all property lookups, not just array indexing. x.foo is actually equivalent to x["foo"], and the same syntax works for arrays since arrays are just objects. Classes in Javascript are just objects that have a prototype property, which is itself an object. It contains a list of default attributes, and if you instantiate a class and look up a property that isn't in the object, it'll search for it in the prototype. So, looking at the code:
mc["sum"]([1, 2, 3])
It searches for a "sum" property in mc, and can't find any since you haven't defined one, so it searches in the prototype of MyChain, and finds the mc method. Thus, mc["sum"] is the sum method of mc. Now, this code:
console.log(mc["sum"]([1, 2, 3, 4]).mc["subtract"](5).value);
doesn't work, and it looks very off for a reason. mc["sum"]([1, 2, 3, 4]) returns mc, so why would you have to access the mc property (not that the mc property even exists)? That's why your second example, the one that calls subtract directly, works:
console.log(mc["sum"]([1, 2, 3, 4])["subtract"](5).value);
Now, let's look at the working code:
const mc = new MyChain();
interface IChainObject {
action: string;
operand: number | number[];
}
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4, 5] },
{ action: "subtract", operand: 5 },
];
let myChain = {};
chainObj.forEach((o) => {
myChain = mc[o.action](o.operand);
});
console.log("myChain is", myChain["value"]);
You actually don't need a lot of this code. It can be simplified down to:
const mc = new MyChain();
interface IChainObject {
action: keyof MyChain;
operand: number | number[];
}
const chainObj: IChainObject[] = [
{ action: "sum", operand: [1, 2, 3, 4, 5] },
{ action: "subtract", operand: 5 },
];
chainObj.forEach((o) => {
// bypass typescript type checking with cast
(mc[o.action] as Function)(o.operand);
});
console.log("myChain is", mc.value);
Essentially, the forEach loops through the elements in chainObj in order. The element's value is stored in the variable o. mc[o.action] takes the method name stored in o.action, and accesses it using square brackets. This is basically looking up the method. Then, the method is called with (o.operand) (in Javascript functions are just values, and you can call any value like a function, but if it's not a function it'll error). mc then modifies itself, and you move on to the next loop. If we insert a debugger statement in the function then break on the first loop, we can inspect the variables:
As you can see, the value starts off at 0, o.action is "sum", and mc[o.action] is the sum method. We can then call the sum method with o.operand, which adds the elements up and sets the value to 15. Then, in the second loop:
mc[o.action] is the subtract method, and we call it with o.operand, which is 5, lowering the value to 10.
Most things in Javascript, like classes are basically just objects.1
What that means is that attributes, or in this case - functions, can be accessed via the dot notation or bracket notation.
Lets look at an example that might assist the explanation:
class MyClass {
myFunction(x) {
console.log(x);
}
}
const x = new MyClass();
// attribute accessed via the dot notation
x.myFunction("Hello World!");
// attribute accessed via the bracket notation and a string
x['myFunction']("Hello World, again!");
// attribute accessed via a variable that is a string
const functionName = 'myFunction';
x[functionName]("Well uh, Hello World again?");
// attribute accessed via a variable that is a string, and passing in an argument
const argument = "This is " + "an argument";
x[functionName](argument);
To illustrate the point further:
class MyClass {
myFunction(x) {
console.log(x);
}
}
const x = new MyClass();
console.log(x.myFunction) // returns a function
console.log(x["myFunction"]) // returns a function
// executing the function
x.myFunction("Method One");
x["myFunction"]("Method Two")
We can see that the returned function can be called.
So let's get back to your example
chainObj.forEach((o) => {
myChain = mc[o.action](o.operand);
});
o.action is the function name
o.operand is the argument
Therefore, what is roughly translates to is:
chainObj.forEach((o) => {
myChain = mc[functionName](arugment);
});
just like our previous examples.
1 "classes are basically just objects"
There are so many pieces of this; I'm just going to focus on "what's the secret that makes the forEach() code work?"
The "secret" is that instances of MyChain have a property named value that gets updated after each method is called. The code with forEach() is not really chaining calls together; it just operates on the original MyChain variable named mc each time.
Since all the methods of MyChain that update this.value also return this, it happens not to matter whether you really chain calls (operate on the return value of each method call):
const chaining = new MyChain();
console.log(chaining.add(3).subtract(1).value); // 2
or if you just call methods on the original object in succession:
const notChaining = new MyChain();
notChaining.add(3);
notChaining.subtract(1);
console.log(notChaining.value) // 2
If you want there to be a difference between those, you can show it by making two versions of MyChain; one that only works via chaining, and one that only works in succession.
The following requires chaining because it never updates the original object and method calls return new objects with the results of the method call:
class RealChain {
constructor(public value: number = 0) { }
sum(args: number[]) {
return new RealChain(args.reduce((s, c) => s + c, 0));
}
add(v: number) {
return new RealChain(this.value + v);
}
subtract(v: number) {
return new RealChain(this.value - v);
}
}
const realChaining = new RealChain();
console.log(realChaining.add(3).subtract(1).value); // 2
const notRealChaining = new RealChain();
notRealChaining.add(3);
notRealChaining.subtract(1);
console.log(notRealChaining.value) // 0
and the following prohibits chaining, because it only updates the original object and its methods don't return anything:
class NotChain {
value: number = 0;
constructor() {
this.value = 0;
}
sum(args: number[]) {
this.value = args.reduce((s, c) => s + c, 0);
}
add(v: number) {
this.value = this.value + v;
}
subtract(v: number) {
this.value = this.value - v;
}
}
const realNotChaining = new NotChain();
realNotChaining.add(3);
realNotChaining.subtract(1);
console.log(realNotChaining.value) // 2
const badNotChaining = new NotChain();
console.log(badNotChaining.add(3).subtract(1).value); // error!
// badNotChaining.add(3) is undefined so you can't call subtract() on it
The code with forEach() would only work with NotChain instances and not with RealChain instances.
If you want a programmatic loop-like thing that actually works with chaining and not calling methods on an original object, you should probably use reduce() instead of forEach():
const realChainReduced = chainObj.reduce(
(mc, o) => mc[o.action](o.operand),
new RealChain() // or MyChain, doesn't matter
);
console.log("realChainReduced is", realChainReduced.value); // 10
Note that I didn't cover any of the other parts, including TypeScript specifics (the typings used here give some compiler errors), so be warned.
Playground link to code
following the snippet bellow, why an array with one position is not working properly when using IN operation?
You can see that with 2 item the operation works fine.
Why this is happening?
What's the work around?
// helper function
function showResult(result) {
document.querySelector('#result').innerHTML += result+'<br/>';
}
var a = ["1"]
var b = "1"
showResult(b in a);
//false
var a = ["1","2"]
var b = "1"
showResult(b in a);
//true
<div id="result"></div>
That's not what in is for. in is not for searching an array for an element. It's for searching an object for a key.
Example:
var x = {a: 1, b: 2};
console.log('a' in x); // true
Your 2nd example works because the array (object) a contains a key called 1.
The in operator checks if an object has a key, not a value. Your second case returns true because any array with two elements has keys '0' and '1'. It doesn't matter that '1' also happens to be a value in that array; '1' in ['foo', 'bar'] is also true.
To test if an element is in an array, you should use Array.prototype.indexOf or in modern engines Array.prototype.includes. You can use the polyfill from either of those links to get support for that method in all engines:
// Most engines (IE 9+)
showResult( a.indexOf( b ) >= 0 );
// Modern engines only:
showResult( a.includes( b ) );
The first result is false because a does not have an index 1, while the second version of a has that index.
The in operator is not about affirming values, but properties (keys).
The confusion is maybe because CoffeeScript does use in for searching values. See here how it translates that into an indexOf
When I use a for ... in loop like:
for(var i in object) {}
I want to know if the object in question is evaluated just once or each time the loop, well, loops.
I made a quick test in my browser (also in node) like:
for(var i in (console.log('INIT'), [1, 2, 3, 4])) { console.log('KEY', i); }
and I get:
INIT
KEY 0
KEY 1
KEY 2
KEY 3
So from this empirical evidence, I could assume that is indeed only evaluated once.
But, is this behavior standard?
From the Mozilla documentation, a for...in loop will iterate over all enumerable properties of the object itself and those the object inherits from its constructor's prototype. An (enumerable) property that is deleted before it has been visited will not be visited later. Properties added to the object over which iteration is occurring may either be visited or omitted from iteration.
In short, the outcome of the example posted by #Amit is not guaranteed, although Chrome and IE may use a different specification for the for ..in loop. However, at least deleting an element seems to prevent it from being visited in Chrome:
var obj = { a: 1, b: 2, c: 3 };
for(var k in obj) {
document.write(k);
delete obj['c'];
}
Bear in mind that (console.log('INIT'), [1, 2, 3, 4]) is an expression that evaluates to [1, 2, 3, 4] so it's not a valid evidence of the issue. A better empirical evidence can be obtained with:
var obj = { a: 1, b: 2, c: 3 };
for(var k in obj) {
document.write(k);
obj.d = 4;
}
And we don't see "d"...
The ECMAScript® Language Specification, section 12.6.4 does not say much about this, except that the expression on the right side is evaluated once and cast to an object:
Let exprRef be the result of evaluating the Expression.
Let experValue be GetValue(exprRef).
If experValue is null or undefined, return (normal, empty, empty).
Let obj be ToObject(experValue).
This says nothing about evaluating any of the keys or values of that object at that time.
In fact, the part that follows the quoted paragraph suggests the keys could be retrieved during the iterations:
Repeat
Let P be the name of the next property of obj whose [[Enumerable]] attribute is true. If there is no such property, return (normal, V, empty).
But there is no requirement in either direction. So, ... this could be implementation (browser) dependent.
When you say that the object is evaluated just once, that can be have different meanings:
The object reference is evaluated just once. This is important when that object is the outcome of an expression, such as a function call. But this is surely taken for granted and not what you mean;
The object's keys (properties) are enumerated once, but the values are retrieved on demand;
The object's keys and values are retrieved once. This could be done at 1 level or nested levels at a potential high memory cost.
This test case shows in my browser (FireFox) the second happens, not the third:
var obj = {a: 1, b: 2, c: 3};
for (key in obj) {
document.write('obj[' + key + '] = ' + obj[key] + '<br>');
if (key=='a') {
// modify a value that is still to be visited
obj["c"] = 4;
// add a key/value pair
obj["d"] = 9;
}
}
Output is (as you can probably also see in your browser):
obj[a] = 1
obj[b] = 2
obj[c] = 4
So the keys were only retrieved once, the values on demand (i.e. not at the start of the loop).
I trying to wrap my head around functional programming in js.
I understand add(3)(5) would be:
function add(x) {
return function(y) {
return x + y;
};
}
How would I change this function so add(3)(5)(7)(8) returns 23 or add(1)(2)(3) returns 6?
you can do something like this.
function add(x) {
return function(y) {
if (y) {
return add(x+y);
}
return x;
};
}
Here, you can call as many times as you want.
add(4)();
add(4)(5)(9)();
add(1)(2)(3)....(n)();
Example link
Without modifying your definition for add, you would need to chain the calls to add to be (add(add(add(3)(5))(7)))(8).
to clarify, this expression breaks down to:
add(3) //returns a function that adds 3
add(3)(5) //returns 8
add(add(3)(5)) // returns a function that adds 8
(add(add(3)(5)))(7) // returns 15
add ((add(add(3)(5)))(7)) //returns function that adds 15
(add(add(add(3)(5))(7)))(8) //returns 23
Breaking it down even further as #zerkms mentioned (and assigning our function definitions to variables) we can see how the chaining of add works:
var add3 = add(3) //returns a function that adds 3
add3(5) //returns 8
var add8 = add(add3(5)) // returns a function that adds 8
add8(7) // returns 15
var add15 = add(add8(7)) //returns function that adds 15
add15(8) //returns 23
By chaining, we are adding on to the result of the previous call to add.
Meaning that if add(3) returns a function that adds 3 and then you add 5 to that number than you can pass that value, 8, into another call to add to make another function that adds 8 to it's argument.
How about:
function add(x) {
return function(y) {
return y == 0 ?
x + y :
add(x + y);
};
}
add(3)(5)(7)(8)(0) // ==> 23
add(1)(2)(3)(0) // ==> 6
The trick here is that it knows when to return a function or the answer by the value of the argument. The "stop" value could be anything really but in my example it's 0 which triggers the answer.
TL;DR
A number cannot be invoked as a function. So use the composite pattern and return a function that has an accumulated result at each iteration. Here is one way to implement add from a factory with tests and example usage: http://jsbin.com/qaqiqu/edit?js,console
Details:
var factory = (function (){
"use strict";
var reduceFactory = function (options) {
var defaultReduce = function (x, y) { return x + y; },//add
noLog = function () {};
function store(x) {
if (options && options.log) {
options.log(x, options.acc, options);
}
options.acc = options.f(options.acc, x);
store.result = options.acc;
return store;
}
//default options
options = typeof options !== 'undefined' ? options : {};
options.f = typeof options.f !== 'undefined' ? options.f : defaultReduce;
options.acc = typeof options.acc !== 'undefined' ? options.acc : 0;
options.log = typeof options.log !== 'undefined' ? options.log : noLog;
return store;
};
return reduceFactory;
}());
//example usage
(function (f) {
var add = f(),
add1 = f(),
add2 = f(),
add3 = f(),
add4 = f(),
clear = function(f) {
return f(-f.result);
};
//how to use a single function
console.log('add(3)(5)(7)(8).result = ' + add(3)(5)(7)(8).result);
clear(add);
console.log('add(1)(2)(3).result = ' + add(1)(2)(3).result);
//how to use factory functions
console.log('add1(3)(5)(7)(8).result = ' + add1(3)(5)(7)(8).result);
console.log('add2(1)(2)(3).result = ' + add2(1)(2)(3).result);
//factory functions can continue to grow as needed
add3(3)(5);
add3(7)(8);
console.log('add3(3)(5); add3(7)(8); add3.result = ' + add3.result);
add4(3);
add4(5);
add4(7);
add4(8);
console.log('add4(3); add4(5); add4(7); add4(8); add4.result = ' + add4.result);
}(factory));
When the add function finally returns a number, then the number cannot be invoked as a function. The normal way around this is to specify how many arguments are required before a number will finally be returned, as suggested in other answers. Some answers suggested a function terminator (0, undefined) as a novel approach, but from the comments, the OP is
"looking for a solution without the need to end with () or (0)"
Using the composite pattern, we can return a function that can also be used as a number by giving it a result property. That way we can keep accumulating the result with an increasing number of function calls. We can use a factory function to create instances of add if we need to do separate additions. Alternatively we can reset a single instance of add to zero when a separate addition is needed.
I have also written a custom set of test assertions with the following passing test cases:
var testCases = [
{arguments: [0], expectedResult: 0},
{arguments: [5, 0, 0, 5, 10, -1], expectedResult: 19},
{arguments: [1], expectedResult: 1},
{arguments: [1, 2], expectedResult: 3},
{arguments: [1, 2, 3], expectedResult: 6},
{arguments: [3, 5, 7, 8], expectedResult: 23},
{arguments: [3, 4], expectedResult: 7},//{acc: 1000}
{arguments: [1, 2], expectedResult: 1003, factoryOptions: {acc: 1000}},
//example tests with logging to debug
//{arguments: [1, 2], expectedResult: 3, factoryOptions: {f: add, log: addLog}},
//{arguments: [3, 4], expectedResult: -7, factoryOptions: {f: sub, log: subLog}},
{arguments: [3, 4], expectedResult: -7, factoryOptions: {f: sub}}
]
I have used inversion of control and made the reduce function an optional parameter to the factory. For example, instead of using add you could use sub (i.e. x - y) as demonstrated in the test cases.
Simply put, the title and the body of the question are about different things.
Firstly, functional programming is not about n-ary functions. You can construct the examples shown before, for instance with recursion (to maintain immutability); however, you then sacrifice the totality of the function. For instance, the 0 terminated functions could crash at runtime if you had external parameters that you didn't validate to be as non-zero.
The solution that would enable totality then either accepts non-zero integers (JavaScript only has 'number' type), and gets called with zero to get the value.
Alternatively, a monad could allow you to combine the properties of a number while returning a function that could be bound further. (But then you wouldn't end up with a pure 'number' but rather a custom 'add' monad. Useful, but has to be implemented.)
Otherwise, the add function could just be a sum of a list. Then it can have from 1 to N elements for computation, it just wouldn't be it's arguments.
Now, as to why variable arity is not very functional, the reasons are pretty fundamental. For one, if you had a function f(a)(b)(c)(d)...(n) what is it's type? Without types, you lose many core aspects of the field. If it always returns type of itself (which is possible, shown by the recursive example) then it's useless as it cannot actually generate side effects. Now to make it useful, while maintaining purity, we cannot just constraint the domain (i.e.) with zero, because then we're 'lying', since zero is a part of valid inputs; the result is just not going to be of the same type as the function. Hence, if we we're to make a wrapper function that validated all inputs as non-0 (and ignored the 0's) and after the last member called 0, we're doing the exact same thing as discussed before, simply in a different manner.
For instance, we could have a 'Maybe number' as an input, and when it's not a number, the result gets returned (thus totality but functionality). Or we could have a list, and after the list is over, we're once again 'detecting' a change (in a different place, i.e, seeing if the size of the vector has been exhausted; or if there's no more members in a list.)
Either way this is implemented, it does the same thing. Difference is in usability, number of bugs, readability, maintainability, accepted data types, language, or perspective.
A note on why is this all so complicated: supplying an argument on its own is the exact same thing as calling the function. Thus f(a)(b)(c)(d) has 4 applications, with none of them being 'the last one', they are ordered, but there's no implicit finite boundary. The creation of which again loops back to my previous statement of how this is the same exact problem with different implementations.
All of the solutions follow this pattern in one way or another. Chaining the binary add operation results in a very similar data flow to the recursion; however, the boundary is hard coded. The recursion is similar to the OOP style where the sum is accumulated and can be retrieved at any point. Which is similar to the 'Add' Monad which would contain both the addition function together with the current state, and so essentially the 'next' user after the add function would discard the function and keep the state.
I think the simplest solution in terms of the given problem is:
[1,2,3,4,5].reduce( function add(sum, x) {sum+x}, 0)