I was asked to create a function to achieve the following, add up some number and then call the value of them all, ie a chained function of sorts, I created a bad solution, but cannot think of a better way of doing this.
add(5).add(10).add(20).value();
The interview question just started with an empty function
function add() {
}
My solution is below, does anybody have any other suggests as I am interested, I've looked at currying, binding etc but not come up with an elegant solution.
var slice = Array.prototype.slice
function add() {
var arr = slice.call(arguments);
return {
add: function() {
arr = arr.concat(slice.call(arguments))
return this;
},
value: function() {
return arr.reduce(function(prev, curr) {
return prev + curr;
});
}
}
};
Edit Just to clarify I was wondering if there is a way to do this without returning an add function but to call the existing add function. I think the way that it has been done below is nice, but I think the interviewer was looking for something non-simple.
3 Answers 3
Why so complicated? Don't carry that array of values around with you. Also, try to stay functional and don't mutate it.
function add(x) {
return {
value: function() {
return x;
},
add: function(y) {
return add(x+y);
}
};
}
The key insight here seems to be that chaining doesn't just mean to return this, but rather any object of the same class. Immutability dictates that it should be a different object when it has a different sum attached to it.
2 Comments
seems overcomplicated tbh, here's my answer but maybe I'm not understanding part of the requirements
function add(x) {
return {
val: 0,
add: function(x) {
this.val += x;
return this;
},
value: function() {
return this.val;
}
}
};
2 Comments
add function, not to the method) doesn't seem to take an argument. And why use arguments[0] instead of just declaring a parameter?I like with your idea of lazy calculation, that's why we should keep the chain of operations. But implementation using array has drawback of mutability (see my comment)
I have just written somewhat close to how I see the solution
var Calculator = function(initialValue){
function createOperator(operation) {
return function(value) {
return createInstance(operation.bind(null, value));
}
}
function createInstance(reduce) {
return Object.freeze({
'add': createOperator((val) => reduce() + val),
'subtract': createOperator((val) => reduce() - val),
'multiply': createOperator((val) => reduce() * val),
'divide': createOperator((val) => reduce() / val),
'value': reduce
});
}
return createInstance(()=>initialValue);
}
Calculator(0).add(5).multiply(4).subtract(12).divide(2).value(); //returns 4
In your problem lazy calculation in not really required, but if we want to preserve chain of operations for multiple use, here it goes. See this example
var Calculation = function(){
function createOperator(operation) {
return function(value) {
return createInstance(operation.bind(null, value));
}
}
function createInstance(apply) {
return Object.freeze({
'add': createOperator((val, initial) => apply(initial) + val),
'subtract': createOperator((val, initial) => apply(initial) - val),
'multiply': createOperator((val, initial) => apply(initial) * val),
'divide': createOperator((val, initial) => apply(initial) / val),
'apply': apply
});
}
return createInstance((initialValue)=>initialValue);
}();
var calc = Calculation.add(5).multiply(2).subtract(11);
calc.apply(2); //returns 3
calc.apply(10); //returns 19
a = add(5).add(6); b=a.add(7)and we havea.value()==b.value()