i'm trying to find a solution to this exercise:
Implement the calculate function that adds an object that gives the ability to do the four
mathematical operations (addition, subtraction, multiplication and division) on the same number and finally print out the result.
function calculate() {
}
const calculator = calculate();
calculator.add(2).add(4).multiply(3).sub(1).sub(3).divide(2).printResult(); // result will be: 7
console.log(calculator)
so, what is the right way to solve this (and if you can add comment will be appreciated
no need to put so many this and function...
in this way you have a closure value.
=> calc_00.val = 20;
will not change the result (it just add a new property if jso is not freeze )
or throw an error in strict mode
"use strict";
function calculate( initVal = 0 ) // default value is zero
{
let
val = initVal // closure value
, jso =
{ add(v) { val += v; return this }
, sub(v) { val -= v; return this }
, multiply(v) { val *= v; return this }
, divide(v) { val /= v; return this }
, printResult() { return val }
}
Object.freeze(jso)
return jso
}
const
calc_00 = calculate()
, calc_10 = calculate(10)
;
// calc_00.yop = ()=>null; // Uncaught TypeError: can't define property "yop": Object is not extensible
// calc_00.sub = ()=>null; // Uncaught TypeError: "sub" is read-only
// calc_00.val = 20; // Uncaught TypeError: can't define property "val": Object is not extensible
calc_00.add(2).add(4).multiply(3).sub(1).sub(3).divide(2);
calc_10.add(10).multiply(3);
console.log( calc_00.printResult(), calc_10.printResult() ) // 7 , 60
You can return the object itselft.
function calculate() {
return {
result: 0,
add: function(num) {
this.result += num;
return this;
},
sub: function(num) {
this.result -= num;
return this;
},
multiply: function (num) {
this.result *= num;
return this;
},
divide: function (num) {
this.result /= num;
return this;
},
printResult: function () {
return this.result;
}
}
};
const calculator = calculate();
const result = calculator.add(2).add(4).multiply(3).sub(1).sub(3).divide(2).printResult(); // result will be: 7
console.log(result);
Make sure to understand how this works in JavaScript. For instance, using functions is different than using arrow functions.
Reference: JavaScript this
Alternative solution using closure
function calculate() {
let result = 0;
return {
add: function(num) {
result += num;
return this;
},
sub: function(num) {
result -= num;
return this;
},
multiply: function (num) {
result *= num;
return this;
},
divide: function (num) {
result /= num;
return this;
},
printResult: function () {
return result;
}
}
};
const calculator = calculate();
const result = calculator.add(2).add(4).multiply(3).sub(1).sub(3).divide(2).printResult(); // result will be: 7
console.log(result);
Related
Function that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times that must multiply the digits in num until it reach a single digit.
var persistenceCount = 0;
function persistence(num) {
var arr = _parseToNumericArray(num);
if (_checkLength(arr)) {
return persistenceCount;
} else {
persistenceCount++;
var newNum = _getMultiple(arr);
persistence(newNum);
}
}
function _parseToNumericArray(num) {
var n = num.toString().split("");
return n.map(function(elem) {
return parseInt(elem);
});
}
function _checkLength(arr) {
return arr.length === 1;
}
function _getMultiple(arr) {
return arr.reduce(function(a, b) {
return a * b;
});
}
console.log(persistence(39)); // Getting output as undefined
Like #Keith said, you forgot to return the value.
var persistenceCount = 0;
function persistence(num) {
var arr = _parseToNumericArray(num);
if (_checkLength(arr)) {
return persistenceCount;
} else {
persistenceCount++;
var newNum = _getMultiple(arr);
return persistence(newNum);
}
}
function _parseToNumericArray(num) {
var n = num.toString().split("");
return n.map(function(elem) {
return parseInt(elem);
});
}
function _checkLength(arr) {
return arr.length === 1;
}
function _getMultiple(arr) {
return arr.reduce(function(a, b) {
return a * b;
});
}
console.log(persistence(39)); // Outputs 3
There is no return statement in the else. So return undefined.
By default, in JavaScript, a function always return undefined if nothing is returned.
update
solution works in foreach loop but not in for loop
function x(number){
return number - 10;
}
var i = 0
var runtimefunctions = {};
var allLevels = {"1":"State","2":"Educational_Services","3":"Principal_Networks","4":"Schools"}
for (var key in allLevels) {
runtimefunctions[i] = function() { return x(i); };
i++;
};
console.log(runtimefunctions[1]()); // -6
console.log(runtimefunctions[2]()); // -6
console.log(runtimefunctions[3]()); // -6
tried hard to make functions but it's first time to create such thing so cant understand the proper way...
I have a function..
function x(number){
return number - 10;
}
runtimefunctions = {};
now I have a loop to run
[1,2,3].forEach(function(y){
//here I want to create a function.. which will make a function x(y) -- like this
runtimefunctions[x] = new Function("return function x_" + levelIterator + "(levelIterator){ console.log(levelIterator); x(" + y + ") }")();
});
so basically..want to make functions like this.
runtimefunctions= {
"1": x(1),
"2": x(2),
and so on
}
Is this what you need?
function x(number){
return number - 10;
}
var runtimefunctions = {};
[1,2,3].forEach(function(y){
runtimefunctions[y] = function() { return x(y); };
});
console.log(runtimefunctions[1]()); // -9
console.log(runtimefunctions[2]()); // -8
console.log(runtimefunctions[3]()); // -7
To satisfy your next (for-in) requirement, you need to closure the index variable with additional function call:
var runtimefunctions = {}, i = 0;
var allLevels = {"1":"State","2":"Educational_Services","3":"Principal_Networks","4":"Schools"}
for (var key in allLevels) {
runtimefunctions[i] = function(index){ return function() { return x(index); } }(i++);
};
It is much easier.
For example:
const createFunctionWith = (x) => {
return (param) => console.log(x, param)
}
let a = [1,2,3].map(x => createFunctionWith(x));
console.log(a[1]("bebe")); // 2, "bebe"
https://jsfiddle.net/muLxoxLd/
You could do something like this
// Found in your code
var x = (a) => {
console.log(a)
};
var runtimefunctions = {};
[1, 2, 3].forEach(function(y) {
//Create a function with a parameter named "levelIterator"
runtimefunctions[y] = Function("levelIterator", "{ console.log(levelIterator); x(" + y + ") }");
});
runtimefunctions[1]('test')
I have tried writing the below code to find sum of 'n' numbers using sum function. I am getting the correct response in output. But i am unable to return that using sum function, as i always have to return a function, which is required for curried effect.
Please help. Thanks in advance.
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
sumCurried.val = function() {
return output;
}
return sumCurried;
}
debugger;
document.getElementById('demo').innerHTML = sum(1, 2)(3)(4);
// document.getElementById('demo').innerHTML = sum(1)(3)(4);
<p id='demo'></p>
enter code here
You can add a stop condition to the curried function, for example - if the function is called without an argument return the output:
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
if(args.length === 0) {
return output;
}
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
return sumCurried;
}
console.log(sum(1, 2)(3)(4)());
<p id='demo'></p>
The returned curry function has a val property, which is a function that returns the current value:
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
sumCurried.val = function() {
return output;
}
return sumCurried;
}
console.log(sum(1, 2)(3)(4).val());
<p id='demo'></p>
Why would you use currying at all? However, here is a shorter version:
const sum = (...args) => {
const func = (...s)=> sum(...args,...s);
func.value = args.reduce((a,b)=>a+b,0);
return func;
};
//usable as
sum(1,2).value,
sum(1,1)(1).value,
sum(1,1)(1,1)(1,1).value
And you always need to end the currying chain. However, it can be shortified:
func.valueOf = ()=> args.reduce((a,b)=>a+b,0);
//( instead of func.value = ... )
So when called you can do:
+sum(1,2,3)
+sum(1)(1)(1)
Using ES5, how do you curry a function that takes infinite arguments.
function add(a, b, c) {
return a + b + c;
}
The function above takes only three arguments but we want our curried version to be able to take infinite arguments.
Hence, of all the following test cases should pass:
var test = add(1);
test(2); //should return 3
test(2,3); //should return 6
test(4,5,6); //should return 16
Here is the solution that I came up with:
function add(a, b, c) {
var args = Array.prototype.slice.call(arguments);
return function () {
var secondArgs = Array.prototype.slice.call(arguments);
var totalArguments = secondArgs.concat(args);
var sum = 0;
for (i = 0; i < totalArguments.length; i++) {
sum += totalArguments[0];
}
return sum;
}
}
However, I have been told that it's not very “functional” in style.
Part of the reason your add function is not very "functional" is because it is attempting to do more than just add up numbers passed to it. It would be confusing for other developers to look at your code, see an add function, and when they call it, get a function returned to them instead of the sum.
For example:
//Using your add function, I'm expecting 6
add(1,2,3) //Returns another function = confusing!
The functional approach
The functional approach would be to create a function that allows you to curry any other functions, and simplify your add function:
function curry(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
return fn.apply(this, args.concat(
Array.prototype.slice.call(arguments, 0)
));
}
}
function add() {
var args = Array.prototype.slice.call(arguments);
return args.reduce(function (previousValue, currentValue) {
return previousValue + currentValue;
});
}
Now, if you want to curry this function, you would just do:
var curry1 = curry(add, 1);
console.log(
curry1(2), // Logs 3
curry1(2, 3), // Logs 6
curry1(4, 5, 6) // Logs 16
);
//You can do this with as many arguments as you want
var curry15 = curry(add, 1,2,3,4,5);
console.log(curry15(6,7,8,9)); // Logs 45
If I still want to add 1, 2, 3 up I can just do:
add(1,2,3) //Returns 6, AWESOME!
Continuing the functional approach
This code is now becoming reusable from everywhere.
You can use that curry function to make other curried function references without any additional hassle.
Sticking with the math theme, lets say we had a multiply function that multiplied all numbers passed to it:
function multiply() {
var args = Array.prototype.slice.call(arguments);
return args.reduce(function (previousValue, currentValue) {
return previousValue * currentValue;
});
}
multiply(2,4,8) // Returns 64
var curryMultiply2 = curry(multiply, 2);
curryMultiply2(4,8) // Returns 64
This functional currying approach allows you take that approach to any function, not just mathematical ones. Although the supplied curry function does not support all edge cases, it offers a functional, simple solution to your problem that can easily be built upon.
Method 1: Using partial
A simple solution would be to use partial as follows:
Function.prototype.partial = function () {
var args = Array.prototype.concat.apply([null], arguments);
return Function.prototype.bind.apply(this, args);
};
var test = add.partial(1);
alert(test(2)); // 3
alert(test(2,3)); // 6
alert(test(4,5,6)); // 16
function add() {
var sum = 0;
var length = arguments.length;
for (var i = 0; i < length; i++)
sum += arguments[i];
return sum;
}
Method 2: Single Level Currying
If you only want one level of currying then this is what I would do:
var test = add(1);
alert(test(2)); // 3
alert(test(2,3)); // 6
alert(test(4,5,6)); // 16
function add() {
var runningTotal = 0;
var length = arguments.length;
for (var i = 0; i < length; i++)
runningTotal += arguments[i];
return function () {
var sum = runningTotal;
var length = arguments.length;
for (var i = 0; i < length; i++)
sum += arguments[i];
return sum;
};
}
Method 3: Infinite Level Currying
Now, here's a more general solution with infinite levels of currying:
var add = running(0);
var test = add(1);
alert(+test(2)); // 3
alert(+test(2,3)); // 6
alert(+test(4,5,6)); // 16
function running(total) {
var summation = function () {
var sum = total;
var length = arguments.length;
for (var i = 0; i < length; i++)
sum += arguments[i];
return running(sum);
}
summation.valueOf = function () {
return total;
};
return summation;
}
A running total is the intermediate result of a summation. The running function returns another function which can be treated as a number (e.g. you can do 2 * running(21)). However, because it's also a function you can apply it (e.g. you can do running(21)(21)). It works because JavaScript uses the valueOf method to automatically coerce objects into primitives.
Furthermore, the function produced by running is recursively curried allowing you to apply it as many times to as many arguments as you wish.
var resultA = running(0);
var resultB = resultA(1,2);
var resultC = resultB(3,4,5);
var resultD = resultC(6,7,8,9);
alert(resultD + resultD(10)); // 100
function running(total) {
var summation = function () {
var sum = total;
var length = arguments.length;
for (var i = 0; i < length; i++)
sum += arguments[i];
return running(sum);
}
summation.valueOf = function () {
return total;
};
return summation;
}
The only thing you need to be aware of is that sometimes you need to manually coerce the result of running into a number by either applying the unary plus operator to it or calling its valueOf method directly.
Similar to the above problem. Sum of nth level curry by recursion
Trick: To stop the recursion I'm passing last () as blank**
function sum(num1) {
return (num2) => {
if(!num2) {
return num1;
}
return sum(num1 + num2);
}
}
console.log('Sum :', sum(1)(2)(3)(4)(5)(6)(7)(8)())
There is more generic approach by defining a curry function that takes minimum number of arguments when it evaluates the inner function. Let me use ES6 first (ES5 later), since it makes it more transparent:
var curry = (n, f, ...a) => a.length >= n
? f(...a)
: (...ia) => curry(n, f, ...[...a, ...ia]);
Then define a function that sums all arguments:
var sum = (...args) => args.reduce((a, b) => a + b);
then we can curry it, telling that it should wait until at least 2 arguments:
var add = curry(2, sum);
Then it all fits into place:
add(1, 2, 3) // returns 6
var add1 = add(1);
add1(2) // returns 3
add1(2,3) // returns 6
add1(4,5,6) // returns 16
You can even skip creating add by providing the first argument(s):
var add1 = curry(2, sum, 1);
ES5 version of curry is not as pretty for the lack of ... operator:
function curry(n, f) {
var a = [].slice.call(arguments, 2);
return a.length >= n
? f.apply(null, a)
: function () {
var ia = [].slice.call(arguments);
return curry.apply(null, [n, f].concat(a).concat(ia));
};
}
function sum() {
return [].slice.call(arguments).reduce(function (a, b) {
return a + b;
});
};
The rest is the same...
Note: If efficiency is a concern, you may not want to use slice on arguments, but copy it to a new array explicitly.
Bit late in this game, but here is my two cents. Basically this exploits the fact that functions are also objects in JavaScript.
function add(x) {
if (x === undefined) {
return add.numbers.reduce((acc, elem) => acc + elem, 0);
} else {
if (add.numbers) {
add.numbers.push(x);
} else {
add.numbers = [x];
}
}
return add;
}
Infinite sum with currying, you can pass a single parameter or multiple up-to infinite:
function adding(...arg) {
return function clousureReturn(...arg1) {
if (!arguments.length) {
let finalArr = [...arg, ...arg1];
let total = finalArr.reduce((sum, ele) => sum + ele);
return total;
}
return adding(...arg, ...arg1)
}
}
This is my solution for single level currying
function sum() {
let args = [...arguments];
let total = args.reduce((total,num) => total + num,0);
return total;
}
console.log(sum(1,2,3,4)) // 10
and the solution for infinite level currying
let sum= function (...args1) {
let total =args1.reduce((total,num) => total + num,0)
return function(...args2) {
if(args2.length!== 0) {
let total2 = args2.reduce((total,num)=>total + num,0);
return sum(total,total2);
}
return total;
};
};
console.log(sum(2,3,4)(2,3)(1)()); // 15
Simple solution
const add = (one) => { // one: Parameter passed in test
return (...args) => {
// args: Array with all the parameters passed in test
return one + args.reduce((sum, i) => sum + i, 0) // using reduce for doing sum
}
}
var test = add(1);
console.log(test(2)); //should return 3
console.log(test(2, 3)); //should return 6
console.log(test(4, 5, 6)); //should return 16
I totally understand why a callback function can't return a value if the logic inside the callback is doing or fetching something on an external server.
What I don't quite get is why does a callback function not return a value if everything inside the callback function is normal, synchronous code:
var myFunc = function(input, callback){
var sum = input + 10;
callback(sum);
};
sum = myFunc(1000, function(input){
console.log(input);
return input + 9000;
});
sum still returns undefined, even though the console.log logs a value of 1010.
Is it a hard and fast rule that callbacks can NEVER return anything?
And do all callbacks in other languages also never return anything?
EDIT
Here's a more complicated example - which also doesn't return anything
discounts = [
{
sku: "126D",
title: "Discount for using 126",
discountCode: "LOVE126",
discountAmount: -2500,
check: function(orderFormContents, callback) {
var discountsApplied = orderFormContents.discountsApplied;
var sqft = orderFormContents.propertyInfo.sqft;
for (var i = discountsApplied.length - 1; i >= 0; i--) {
if (discountsApplied[i].discountCode === this.discountCode) {
if (sqft < 1501) {
return callback('', 'Coupon Added', this.discountAmount);
} else {
return callback('', 'Coupon Added', (this.discountAmount + -2500));
};
};
};
}
},
// additional discount objects in array
];
var checkDiscount = function(code, orderFormContents, allDiscounts) {
for (var i = allDiscounts.length - 1; i >= 0; i--) {
if (allDiscounts[i].discountCode === code) {
allDiscounts[i].check(orderFormContents, function(error, message, amount) {
var result = {
"error": error,
"message": message,
"amount": amount
};
debugger
return result;
});
};
};
};
var orderFormContents = {
propertyInfo: {
sqft: 1000
},
discountsApplied: [
{
discountCode: "LOVE126"
}
]
};
var discountCode = "LOVE126";
var result = checkDiscount(discountCode, orderFormContents, discounts);
debugger
console.log(result);
You're missing the return statement in myFunc.
var myFunc = function(input, callback){
var sum = input + 10;
return callback(sum);
};
sum = myFunc(1000, function(input){
console.log(input);
return input + 9000;
});
For extra clarification, there's nothing terribly special about your callback in this example. If you chain functions, you just need to make sure you return each result. We could rewrite the current example as:
function myInnerFunc(sum) {
return sum + 9000;
}
function myFunc (input){
var sum = input + 10;
return myInnerFunc(sum);
}
var sum = myFunc(1000);
But, the nature of first-class functions in JavaScript allows us to pass functions around. This becomes interesting in functional programming, where one function can now be passed various other functions for different results.
function add (a, b) {
return a + b;
}
function multi (a, b) {
return a * b;
}
var list = [1, 2, 3, 4, 5];
console.log(list.reduce(add)); // 15
console.log(list.reduce(multi)); // 120
Asynchronous operations fire their callbacks at some later time, so they can't be used to return values right away. The easiest example of this is setTimeout which calls its callback after N milliseconds. In this example myFunc will have returned long before the setTimeout has had a chance to fire its callback. Same logic can be applied to AJAX callbacks.
function myFunc (value) {
var val;
window.setTimeout(function () {
val = value;
}, 1000)
return val;
}
var test = myFunc(1000)
console.log(test); // undefined
Answer Part 2: Electric Boogaloo
You're still missing a return.
This line
var result = checkDiscount(discountCode, orderFormContents, discounts);
assigns the result from checkDiscount, but that function doesn't return anything.
var checkDiscount = function(code, orderFormContents, allDiscounts) {
for (var i = allDiscounts.length - 1; i >= 0; i--) {
if (allDiscounts[i].discountCode === code) {
allDiscounts[i].check(orderFormContents, function(error, message, amount) {
var result = {
"error": error,
"message": message,
"amount": amount
};
return result;
});
}
}
// Never returned, default return value is undefined
};
You can fix this by returning properly.
var checkDiscount = function(code, orderFormContents, allDiscounts) {
for (var i = allDiscounts.length - 1; i >= 0; i--) {
if (allDiscounts[i].discountCode === code) {
return allDiscounts[i].check(orderFormContents, function(error, message, amount) {
var result = {
"error": error,
"message": message,
"amount": amount
};
return result;
});
}
}
};
Honestly, this code is really looptastic, and could most likely be refactored into something more concise.