JavaScript - Modify arguments before executing function - javascript

Given I have a function called sum module imported from a 3rd party module Calculator. Here's how I use it:
Calculator.sum(1, 2) // returns 3
I don't know the implementation of Calculator.sum. What if I want to modify the arguments passed to Calculator.sum before executing sum, so that instead of taking the original numbers (1, 2, 3, etc), sum will take their squared values (1, 4, 9, etc) ? For example:
Calculator.sum(1, 2) // returns 5
Calculator.sum(2, 3) // returns 13
Calculator.sum(3, 4) // returns 25
Note: This is just an example of my actual problem, I don't actually need a Calculator.sum function to calculate sum of squares 😀

Couldn't you just store it under another name and overwrite it ?
Calculator.sum_stored = Calculator.sum;
Calculator.sum = function(a,b){
return Calculator.sum_stored(Math.sqrt(a),Math.sqrt(b));
};
Then you can just call Calculator.sum as you wanted to.

You could simply decorate the original function with you extra functionality, then call the original function with whatever values you wish.
If you are going to do something like this, you should really define a different function eg, calulator.squareAdd.
// this is your library object
const Calculator = {
sum: (...args) => args.reduce((x, y) => x + y, 0)
}
console.log(
'before decoration',
Calculator.sum(1, 2)
)
// save a reference to the original function
const origSum = Calculator.sum
// decorate the sum function with your own function
Calculator.sum = function(...args) {
return origSum.apply(Calculator, args.map(x => Math.pow(x, 2)))
}
// call the decorated function
console.log(
'after decoration',
Calculator.sum(1, 2), // returns 5
Calculator.sum(2, 3), // returns 13
Calculator.sum(3, 4) // returns 25
)
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>

You can modify the arguments in side the method like this ->
Calculator.sum(a,b) {
return a*a + b*b;
}
And if you want your method to be flexible then you can pass a third argument that will identify what operation needs to be performed on the arguments.
Calculator.sum(a,b,'square'){
//use switch case here to return the correct result.
}

Related

Closure with a Lazy Adder Function

I'm stuck on a problem that uses a closure function to add the arguments of subsequent functions into a sum function:
Write a function named: lazyAdder(firstNum). The lazyAdder function
will accept a number and return a function. When the function returned
by lazyAdder is invoked it will again accept a number, (secondNum),
and then return a function. When the last mentioned function is
invoked with a number, (thirdNum), it will FINALLY return a number.
See below for examples!
Example 1:
let firstAdd = lazyAdder(1);
let secondAdd = firstAdd(2);
let sum = secondAdd(3);
console.log(sum); // prints 6
Example 2:
let func1 = lazyAdder(10);
let func2 = func1(20);
let total = func2(3);
console.log(total); // prints 33
I tried:
const lazyAdder = f => g => h => x => f(g(h))(h(x));
Thinking it takes in two function inputs (firstNum + secondNum = sum1), then adds a third (thirdNum + sum1 = sum2).
This did invoke the function twice; however, it did not return the sum - it returned an anonymous function.
If I get it correctly, what you are tasked to do is to perform a sum in a sequence of evaluations (i.e. pass arguments at different times). In a non-lazy approach, you would simply make a function sum which takes 3 parameters x, y and z and sum this: sum(1, 2, 3) = 7. Now to do this the "lazy" way, you have to perform an operation on this function called currying. I suggest reading up on this, as this is essentially what is asked.
Currying such a function can be done quite easily in JavaScript. As you showed, you can just chain the arguments in a function declaration:
const func = arg1 => arg2 => arg3 => ... // Some logic performed here
Now you can call this function 3 times until it returns something other than a closure; a value.
How do you make sure that when you func(1)(2)(3) it returns the sum, which is 6?
Since I suspect this is a homework assignment, I do not want to give you the plain answer. Therefore, it is up to you to define what logic should be put inside the function to sum these values. What is important is that the definition I gave, is already a definition of lazy evaluation.

How do I create a function that accepts multiple arguments to perform an arithmetic calculation in JavaScript?

I want to write a function that performs arithmetic on ALL the arguments supplied. So for instance, if I do:
calculate('+', 3, 5, 6)
It should return 14 (which is 3+5+6)
Or if I do
calculate('*', 6,3,6,8,)
It should return 864 (which is the equivalent of multiplying all those numbers).
The function should essentially be able to handle any amount of numbers I supply to it, while also being able to handle the main arithmetic operators such as + - / *
I'm new at programming. I've tried:
function mCalc(_operator){
if(_operator=='+'){
return arguments + arguments;
}
}
console.log(mCalc('+',5,5));
this is not working so i can't even move forward.
In each function you have an arguments object see the section Rest, default, and destructured parameters as it states:
The arguments object can be used in conjunction with rest, default, and destructured parameters.
function foo(...args) { return args; }
Once you have all the arguments which are needed for your calculation just use Array.prototype.reduce(). As the documentation which states:
The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
I guess you can use as the following:
const mCalc = (_operator, ...args) => {
if(_operator === '+') {
return args.reduce((a, c) => a + c, 0);
}
// rest what you want to implement
}
const result = mCalc('+', 3, 5, 6, 2);
console.log(result);
I hope that helps!
You could take an object for the operators and reduce the values by using a function which returns a function for two operands.
By calling the function the operator is taken and the values are taken to an array by using rest parameters ....
This approach uses arrow functions, like
calculate = (op, ...values) => values.reduce(take(op));
^^^^^^^^^ name of the function/variable
^^^^^^^^^^^^^^^ parameters
^^ arrow
^^^^^^^^^^^^^^^^^^^^^^^ return value
const
operators = {
'+': (a, b) => a + b,
'*': (a, b) => a * b
},
take = op => operators[op],
calculate = (op, ...values) => values.reduce(take(op));
console.log(calculate('+', 3, 5, 6)); // 14
console.log(calculate('*', 6, 3, 6, 8));

How can this function work with a missing parameter

How can callback function work with one parameter when it requires 2 (selector and data) to go? Why doesn't it throw an error?
let links = document.querySelectorAll("a");
links.forEach(function(link){
link.addEventListener("click",function(e){
e.preventDefault();
ajax("get",e.target.href,render)
})
})
function ajax(url,metodo,callback){
let xhr = new XMLHttpRequest
xhr.open(metodo,url)
xhr.addEventListener("load",function(){
if(xhr.status==200){
callback(xhr.response)
}
})
xhr.send()
}
function render(selector,data){
document.querySelector(selector).innerHTML = data
}
In javascript, it is not necessary to call with same number of parameters as defined in function definition. If we do not define a default parameter value in function definition, then parameter becomes type of undefined.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters
Default function parameters allow formal parameters to be initialized
with default values if no value or undefined is passed.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
Starting with ECMAScript 2015, there are two new kinds of parameters:
default parameters and rest parameters.
Default parameters: In JavaScript, parameters of functions default to
undefined. However, in some situations it might be useful to set a
different default value. This is where default parameters can help.
In the past, the general strategy for setting defaults was to test
parameter values in the body of the function and assign a value if
they are undefined. If in the following example, no value is provided
for b in the call, its value would be undefined when evaluating a*b
and the call to multiply would have returned NaN. However, this is
caught with the second line in this example:
function multiply(a, b) {
b = typeof b !== 'undefined' ? b : 1;
return a * b;
}
multiply(5); // 5
With default parameters, the check in the function body is no longer necessary. Now, you can simply put 1 as the default
value for b in the function head:
function multiply(a, b = 1) {
return a * b;
}
multiply(5); // 5
For more details, see default parameters in the reference.
Rest parameters: The rest parameter syntax allows us to represent an
indefinite number of arguments as an array. In the example, we use the
rest parameters to collect arguments from the second one to the end.
We then multiply them by the first one.
function multiply(multiplier, ...theArgs) {
return theArgs.map(x => multiplier * x);
}
var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]
Argument Object:
Using the arguments object, you can call a function with more
arguments than it is formally declared to accept. This is often useful
if you don't know in advance how many arguments will be passed to the
function. You can use arguments.length to determine the number of
arguments actually passed to the function, and then access each
argument using the arguments object.
For example, consider a function that concatenates several strings.
The only formal argument for the function is a string that specifies
the characters that separate the items to concatenate. The function is
defined as follows:
function myConcat(separator) {
var result = ''; // initialize list
var i;
// iterate through arguments
for (i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
You can pass any number of arguments to this function, and it
concatenates each argument into a string "list":
// returns "red, orange, blue, "
myConcat(', ', 'red', 'orange', 'blue');
// returns "elephant; giraffe; lion; cheetah; "
myConcat('; ', 'elephant', 'giraffe', 'lion', 'cheetah');
// returns "sage. basil. oregano. pepper. parsley. "
myConcat('. ', 'sage', 'basil', 'oregano', 'pepper', 'parsley');
To make it throw error, if same number of argument is not passed in function, typescript can be used.

Currying function with unknown arguments in JavaScript

In a recent interview, I was asked to write a function that adds numbers and accepts parameters like this:
add(1)(2)(3) // result is 6
add(1,2)(3,4)(5) // result is 15
The number of parameters is not fixed, and the arguments can be either passed in sets or individually.
How can I implement this add function?
Given your examples, the number of parameters is fixed in some ways.
As #ASDFGerte pointed out, your examples seem to return the result after three invocations. In this case a simple implementation without introducing terms like variadic and currying could be
function add(...args1){
return function(...args2){
return function(...args3){
return args1.concat(args2).concat(args3).reduce((a,b)=>a+b)}}}
console.log(add(1)(2)(3))
console.log(add(1,2)(3,4)(5))
Every invocation accepts a variable number of parameters.
However it would be nice to generalize the construction of this nested functions structure and you can accomplish that with currying.
But if you want to allow an arbitrary number of invocations, when you should stop returning a new function and return the result? There is no way to know, and this is a simple, unaccurate and partial explanation to give you the idea of why they said you cannot accomplish what they asked you.
So the ultimate question is: is it possible that you misunderstood the question? Or maybe it was just a trick to test you
Edit
Another option would be to actually invoke the function when no arguments are passed in, change the call to add(1)(2)(3)()
Here an example recursive implementation
function sum (...args) {
let s = args.reduce((a,b)=>a+b)
return function (...x) {
return x.length == 0 ? s : sum(s, ...x)
};
}
console.log(sum(1,2)(2,3,4)(2)())
At every invocation computes the sum of current parameters and then return a new function that:
if is invoked without parameters just return the current sum
if other numbers are passed in, invokes recursively sum passing the actual sum and the new numbers
I'm a bit late to the party, but something like this would work (a bit hacky though in my opinion):
const add = (a, ...restA) => {
const fn = (b, ...restB) => {
return add([a, ...restA].reduce((x, y) => x + y) + [b, ...restB].reduce((x, y) => x + y))
};
fn.valueOf = () => {
return [a, ...restA].reduce((x, y) => x + y)
};
return fn;
}
This function returns a function with a value of the sum. The tests below are outputing the coerced values instead of the actual functions.
console.log(+add(1,2)(3,4)(5)); // 15
console.log(+add(1)) // 1
console.log(+add(1)(2)) // 3
console.log(+add(1)(2)(3)) // 6
console.log(+add(1)(2)(3)(4)) // 10
Since it's a currying function, it will always return another function so you can do something like this:
const addTwo = add(2);
console.log(+addTwo(5)); // 7
using reduce and spread it can be done as below
function calc(...args1){
return function (...args2){
return function (...args3){
let merge = [...args1, ...args2, ...args3]
return merge.reduce((x ,y)=> x + y) ;
}
}
}
let sum = calc(10)(1)(4);
console.log("sum",sum);
They probably wanted to know how comfortable you were with "javascript internals", such as how and when methods like Function#toString and Function#valueOf, Function#[Symbol.toPrimitive] are called under the hood.
const add = (...numbers) => {
const cadd = (...args) => add(...args, ...numbers);
cadd[Symbol.toPrimitive] = () => numbers.reduce((a, b) => a + b);
return cadd;
}
console.log(
`add(1,2)(3,4)(5) =>`, add(1,2)(3,4)(5),
); // result is 15
console.log(
`add(1,2) =>`, add(1,2),
); // result is 3
console.log(
`add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5) =>`, add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5),
); // result is 32

Javascript: Compose a function with argument placement instructions for each composition

I'm looking for a javascript function that can:
Condition (I)
compose another function when it does not have recursion in its definition, kind of like in maths when the function is given a power, but with multiple arguments possible in the first input - e.g. with a (math) function f:
f(x) := x+2
f5(x) = f(f(f(f(f(x))))) = x+10
Condition (II)
Or maybe even input custom arguments into each step of composition:
(52)2)2=
Math.pow(Math.pow(Math.pow(5,2),2),2) = Math.pow.pow([5,2],2,["r",2]])
//first arg set, how times the next, 2nd arg set - "r" stands for recursion -
//that argument will be occupied by the same function
//Using new solution:
_.supercompose(Math.pow,[[5,2],[_,2],[_,2]]) //-> 390625
2((52)3)=
Math.pow(2,Math.pow(Math.pow(5,2),3)) = Math.pow.pow([5,2],["r",2],["r",3],[2,"r"])
//Using new solution:
_.supercompose(Math.pow,[[5,2],[_,2],[_,3]]) //-> 244140625
_.supercompose(Math.pow,[[5,2],[_,2],[_,3],[2,_]]) //-> Infinity (bigger than the max. number)
Note: The above are just templates, the resulting function doesn't have to have the exact arguments, but the more close to this (or creative, for example, a possibility of branching off like this ->[2,4,"r",4,2,"r"], which would also be complicated) the better.
I've been attempting to do at least (I) with Function.prototype, I came up with this:
Object.defineProperty(Function.prototype,"pow",{writable:true});
//Just so the function not enumerable using a for-in loop (my habit)
function forceSlice(context,argsArr)
{returnArray.prototype.slice.apply(context,argsArr)}
Function.prototype.pow = function(power)
{
var args=power<2?forceSlice(arguments,[1]):
[this.pow.apply(this,[power-1].concat(forceSlice(arguments,[1])))];
return this.apply(0,args);
}
//Usage:
function square(a){return a*a;}
square.pow(4,2) //65536
function addThree(a,b){return a+(b||3); }
// gives a+b when b exists and isn't 0, else gives a+3
addThree.pow(3,5,4) //15 (((5+4)+3)+3)
Worst case, I might just go with eval, which I haven't figured out yet too. :/
Edit: Underscore.js, when played around with a bit, can fulfill both conditions.
I came up with this, which is close to done, but I can't get it to work:
_.partialApply = function(func,argList){_.partial.apply(_,[func].concat(argList))}
_.supercompose = function(func,instructions)
{
_.reduce(_.rest(instructions),function(memo,value)
{
return _.partialApply(_.partialApply(func, value),memo)();
},_.first(instructions))
}
//Usage:
_.supercompose(Math.pow,[[3,2],[_,2]]) //should be 81, instead throws "undefined is not a function"
Edit: jluckin's cleareance of terms (recursion-> function composition)
Edit: made example function return number instead of array
The term you are looking for is called function composition, not necessarily recursion. You can apply function composition in javascript easily since you can pass a function as an argument.
I created a small function called compose, which takes a function, an initial value, and the number of times to compose the function.
function compose(myFunction, initialValue, numberOfCompositions) {
if (numberOfCompositions === 1) {
return myFunction(initialValue);
}
else {
return compose(myFunction, myFunction(initialValue), --numberOfCompositions);
}
}
When this function is evaluated, you pass in some function f(x), some initial x0, and the repeat count. For example, numberOfCompositions = 3 gives f(f(f(x)));
If there is one composition, then f(x) is returned. If there are two compositions, compose returns f(x) with f(x) replacing x as the argument, with 1 passed in as the composition so it will evaluate f(f(x)).
This pattern holds for any number of compositions.
Since functions are treated as objects and can be passed as arguments of functions, this method basically wraps your "non-recursive" functions as recursive functions to allow composition.
Success(simplicity wins):
_.supercompose = function (func,instructions,context)
{
var val;
for(var i = 0; i < instructions.length; i++)
{
val = _.partial.apply(_,[func].concat(instructions[i])).apply(context||this,val?[val]:[]);
}
return val;
}
//Usage (with a function constructor for operations):
_.op = function(o){return Function.apply(this,"abcdefghijklmnopqrstuvwxyz".split("").concat(["return " + o]))}
_.op("a+b")(3,5) //-> 8
_.op("a*b")(3,5) //-> 15
_.supercompose(_.op("(a+b)*c*(d||1)"),[[1,2,3],[-5,_,1],[1,2,_,3]])
//-> (1+2)*((-5+((1+2)*3))*1)*3 -> 36

Categories

Resources