Lodash partial with object path - javascript

Using lodash or arrow functions, what is the more elegant way to rewrite the func declaration in the following example ?
function multiply(a, b) {
return a * b;
}
let foo = {};
let func = function (v) { return multiply(v, _.get(foo, 'bar')) };
foo.bar = 4;
console.log(func(4)); //Result in 16
let foo2 = {};
let func2 = _.unary(_.partialRight(multiply, _.get(foo2, 'bar')));
foo2.bar = 4;
console.log(func2(4)); //Result in NaN
let foo3 = {};
let func3 = (v) => multiply(v, _.get(foo3, 'bar'));
foo3.bar = 4;
console.log(func3(4)); //Result in NaN
I tried with arrow function and partial but can't get it to work as you can see

Your third option is working.
The second option is not working, because _.get(foo2, 'bar') get's immediately evaluated and puts foo2.bar in partialRight as a parameter, which is undefined, because the 4 get's assigned later.
Therefore multiply calculates 4 * undefined which is NaN.
Improvements could be:
curry multiply
make func pure
For example:
const multiply = _.curryRight(function(a, b) {
return a * b;
})
let foo3 = {};
foo3.bar = 4;
let func3 = multiply(_.get(foo3, 'bar'));
console.log(func3(4));

Related

Why does the default JS bind function works and why my polyfill for the bind returns undefined?

I am trying to write the polyfill for the js bind function over a multiply function. The js bind function is giving the correct answer 8 but my polyfill is giving undefined. The main multiply function is returning all the params correctly though.
Function.prototype.myBind = function (...args) {
let obj = this;
let params = args.slice(1);
return function (...param2) {
obj.apply(args[0], [...params, ...param2]);
};
};
let mul = (a, b) => {
console.log(13, a, b, a * b);
return a * b;
};
let mulFour = mul.bind(this, 4);
let myMulFour = mul.myBind(this, 4);
console.log(mulFour(2));
console.log(myMulFour(2));
CertainPerformance was correct, needed to return the obj.apply(args[0], [...params, ...param2]); again.
The polyfill would go like this:
Function.prototype.myBind = function (...args) {
let obj = this;
let params = args.slice(1);
return function (...param2) {
return obj.apply(args[0], [...params, ...param2]);
};
};

Passing additional vs one argument into the function

I am implementing compose function using reduceRight menthod as follows
const compose = fns => (...args) =>
fns.reduceRight((acc, fn) => fn(acc, ...[args.slice(1)]), args[0]);
const func3 = (x, y) => (y > 0 ? x + 3 : x - 3);
const func2 = x => x ** 2;
const func1 = x => x - 8;
const fnOne = compose([func1, func2, func3])('3', 1);
console.log(fnOne); // should be 1081
const fnTwo = compose([func1, func2, func3])('3', -1);
console.log(fnTwo); //should be -8
the first function is supposed to receive two arguments and return the result to the next function as the only one argument. The problem is that the first function is passing two arguments to the next function instead of one. Let me know if you have any ideas how to fix it. Any help is very much appreciated.
The problem here is that you're not modifying the args variable.
Let's look at what happens in detail:
At the first call of your reductor, acc becomes func3(args[0], ...[args.shift(1)]) === func3(args[0], args[1], args[2], ...).
At the second call, acc becomes func2(acc, [args.shift(1)]), which is func2(func3(args[0], args[1], args[2], ...), args[1], args[2], ...).
You can already see where the problem lies: args1 is never dropped from the array, because Array.slice() creates a copy and does not modify the actual array.
To solve your problem you should instead use:
const compose = fns => (...args) =>
fns.reduceRight((acc, fn) => fn(acc, ...args.splice(0, fn.length - 1)), args[0]);
You need to call the first function outside the reduceRight() loop, since it's not being called the same way as all the other functions. It gets its arguments from ...args and its value should be used as the initial accumulator argument to reduce.
const compose = fns => (...args) => {
let last = fns.pop();
return fns.reduceRight((acc, fn) => fn(acc), last(...args))
};
const func3 = function(x, y) {
console.log(`func3 got ${arguments.length} arguments`);
return (y > 0 ? x + 3 : x - 3);
};
const func2 = function(x) {
console.log(`func2 got ${arguments.length} arguments`);
return x ** 2;
};
const func1 = function(x) {
console.log(`func2 got ${arguments.length} arguments`);
return x - 8;
};
const fnOne = compose([func1, func2, func3])('3', 1);
console.log(fnOne); // should be 1081
const fnTwo = compose([func1, func2, func3])('3', -1);
console.log(fnTwo); //should be -8

Javascript: return multiple values from different functions

I am trying to return multiple values from different functions.
The starting point is a bidimensional array. An example of the code is:
var items = [[0,1],[1,2],[0,2]];
var a;
var b;
function first() {
a = items[Math.floor(Math.random() * items.length)];
return a;
}
function second() {
b = a[Math.floor(Math.random() * 2)];
return b;
}
function third (){
first();
second();
}
third();
If I write the code outside the functions, everything works fine. When I use functions and replace return with console.log, it works. If I use functions and return (as in the code reported above), it gives me undefined. I didn't find solutions. Why the code isn't working?
Thanks in advance
If you are declaring variable a and b outside function(like in your code) than there is no need to return the values. a and b will get defined.
But if you are not declaring it outside, then store the return values in array variable.
var items = [[0,1],[1,2],[0,2]];
function first() {
a = items[Math.floor(Math.random() * items.length)];
return a;
}
function second() {
b = a[Math.floor(Math.random() * 2)];
return b;
}
function third (){
var a = first();
var b = second();
var arr = [];
arr.push(a);
arr.push(b);
return arr
}
var t = third();
console.log(t[0], t[1]);
If you want third to return values, add a return in it.
function third (){
var a = [];
a.push(first())
a.push(second())
return a;
}
Maybe you want something like
function third (){
return {a: first(), b: second()};
}
then
var t = third()
console.log(t.a, t.b)
or if you're running on ES6
var {a,b} = third()
console.log(a, b)
see Destructuring assignment for further details

New method does not see "this" (JavaScript)

Making a calculator that accepts new methods. But when I add a new method it does not see object's "this". Why Console.log returns "undefined"?
function Calculator() {
this.numbers = function() {
this.numberOne = 2;
this.numberTwo = 5;
},
this.addMethod = function(op, func) {
this[op] = func(this.numberOne, this.numberTwo);
// WHY LOG RETURNS "undefined"?
console.log(this.numberOne);
}
}
let calc = new Calculator();
calc.addMethod("/", (a, b) => (a / b));
document.write(calc["/"]);
You did not define this.numberOne and this.numberTwo before you tried to call the function on it. Moreover, you are printing this.one which is never defined in your code.
If you tried the following snippet:
function Calculator() {
this.numbers = function() {
this.numberOne = 2;
this.numberTwo = 5;
},
this.addMethod = function(op, func) {
this[op] = func(this.numberOne, this.numberTwo);
// WHY LOG RETURNS "undefined"?
console.log(this.numberOne);
}
}
let calc = new Calculator();
calc.numbers();
calc.addMethod("/", (a, b) => (a / b)); // 2/5
document.write(calc["/"]);
Then the code will work as expected because calc.numberOne and calc.numberTwo are defined
Your numbers were not getting initialized.
Also you used this.one what's that? Did you mean numberOne.
Check out the working code below :
function Calculator() {
this.numberOne = 2;
this.numberTwo = 5;
this.addMethod = function(op, func) {
this[op] = func(this.numberOne, this.numberTwo);
// WHY LOG RETURNS "undefined"?
console.log(this.numberOne, this.numberTwo );
}
}
let calc = new Calculator();
calc.addMethod("/", (a, b) => (a / b));
document.write(calc["/"]);

Currying with functions that take unlimited arguments

Lets say i have the following add function that takes an unlimited number of arguments.
function add () {
var total = 0;
var args = Array.prototype.slice.call(arguments, 0);
for (var i=0; i<args.length; i++) {
total += arguments[i];
}
return total;
}
and the following curry function.
function curryFunction(orig_func) {
var ap = Array.prototype;
var args = arguments;
function fn() {
if (arguments.length != 0) {
ap.push.apply(fn.args, arguments);
return fn;
} else {
return orig_func.apply(this, fn.args);
}
};
return function() {
fn.args = ap.slice.call( args, 1 );
return fn.apply( this, arguments );
};
}
I then want to do something like:
var f = curryFunction(add);
var a = f(3)(4)(3);
var b = f(10)(3);
var result1 = a(); // returns 10
var result2 = b(); // returns 13
However i always get 13 for both a() and b() i assume is because in line
fn.args = ap.slice.call(args, 1);
the existing array [3,4,3] is overwriting with []. Can someone please provide me with a hint on how to make this work? Thanks
The problem is that fn is scoped to curryFunction and so is shared between a and b.
All you have to do is move the definition of fn into the anonymous return function. It's then created when you call f, and the problematic fn.args = line is only called once.
Proof: jsFiddle.
Currying a function which takes indefinitely many arguments can be implemented as follows;
Lets say we have a function called addAll() which returns the sum of all provided arguments.
var addall = (...a) => a.reduce((p,c) => p + c);
And we have a curry function which takes a function and returns curried version ad infinitum up until the returned function is called with no arguments, only when the result of all previously provided arguments will be returned. OK here is the curry function.
var curry = f => (...a) => a.length ? curry(f.bind(f,...a))
: f();
Lets see it in action;
var addAll = (...a) => a.reduce((p,c) => p + c),
curry = f => (...a) => a.length ? curry(f.bind(f,...a)) : f(),
curried = curry(addAll),
result = curried(10,11)(10)(37)(10,17,42)();
console.log(result);
result = curried("a","b")("c")("d")("e","f","g")();
console.log(result);

Categories

Resources