I have a reducer function like this
let reducer = (acv, cv) => {
return acv += cv;
}
function createMenus(arr){
let someValue = getNewValue();
arr.reduce(reducer, '');
//I want to bind my above someValue to reducer function so, I can append it to my string like below
}
let reducer = (acv, cv, someValue) => {
return acv += (cv+someValue);
}
I tried of doing something using bind() but not successful.
You can use closures in your code to your advantage.
You can create a function that returns a function.
createMenus below takes one argument and uses the value passed to it, returning another function that will operate in the array's reduce function, so calling reducer(someValue) actually returns another function. That function is what is passed to reduce(in the same way you are doing it above).
function getNewValue() {
return 'foo';
}
function reducer(someValue) {
return (acv, cv) => {
return acv += (cv + someValue);
}
};
function createMenus(arr){
let someValue = getNewValue();
return arr.reduce(reducer(someValue), '');
}
console.log(createMenus(['a', 'b', 'c']));
UPDATE
As #george mentioned in the coments, you could also use arrow functions to accomplish the same thing. The syntax is much shorter, but readability is in the eyes of the beholder.
let reducer = value => (a, v) => a + (v + value);
Even if you find it more readable, it is possible that you will make your code harder to debug utilizing this method as it can be harder to track down an error that occurs in an anonymous function than it is in a named function.
You can access someValue by defining reducer inside another function definition where someValue is available. (This is a use of closures in JavaScript.)
const
myArr = ["big", "medium", "tiny"],
myStr = createMenus(myArr);
console.log(myStr);
function createMenus(arr){
const
someValue = getNewValue(),
reducer = (acv, cv) => acv + (cv + someValue),
output = arr.reduce(reducer, '');
return(output);
}
function getNewValue(){
return "MenuItem, ";
}
Related
I'm solving an exercise that is intended to use closures. You must create a function that returns a function that will store a value and, when you reuse it, add the new value to the saved one.
const firstValue = myFunction(3);
const secondValue = firstValue(4);
// result => 7
this is the code that I'm using to practice closures:
function addNumbers(num) {
let storage = 0
let n = num
function adding(n) {
storage += n;
return storage
}
return adding(n)
}
let firstAttemp = addNumbers(4)
let secondAttemp = firstAttemp(3)
console.log(firstAttemp)
this throw an error "Uncaught TypeError: firstAttemp is not a function"
const addNumbers = (a) => (b) => a + b
It's called currying, more details here.
P.S.
If you want to use function syntax, it will look like this:
function addNumbers(a) {
return function (b) {
return a + b
}
}
As #skara stated in their comment, return adding(n) returns the result of calling adding instead of returning the function so that it may be called later with firstAttemp(3).
Unfortunately though it still doesn't work because you don't actually assign the value passed to addNumber to be added later.
function addNumbers(num) {
let storage = 0;
let n = num;
function adding(n) {
storage += n;
return storage;
}
return adding;
}
let firstAttemp = addNumbers(4);
let secondAttemp = firstAttemp(3);
console.log(firstAttemp);
console.log(secondAttemp); // 3! 😢
You don't actually need to manually save the value of num to a variable as it is captured in the closure arround adding that is being returned.
function addNumbers(num) {
function adding(n) {
return num + n;
return storage;
}
return adding;
}
let firstAttemp = addNumbers(4);
let secondAttemp = firstAttemp(3);
console.log(secondAttemp); // 7 👍🏻
I am having trouble printing the correct result in NodeJS, why isn't my code printing the strings in the correct way ? I feel like console.log is not called at all. Why do I get :
[Function]
[Function]
[Function]
[Function]
Expected result:
Tigrou (buddy of Spider) was here!
Spider (buddy of Tigrou) was also here!
Tigrou (buddy of Spider) are in a boat...
1 (buddy of 2)3
The code I thought would work:
function build_sentence(...args)
{
var i = 0
var s = ""
for (let arg of args)
{
if (i == 1)
{
i++
s += "(buddy of " + arg + ") "
}
else
{
s += arg + " "
i++
}
}
return s
}
function mycurry(build_sentence)
{
return function(...args)
{
if (!args)
{
return build_sentence();
}
else
{
return mycurry(build_sentence.bind(this, ...args))
}
}
}
const curried = mycurry(build_sentence);
console.log(curried("Tigrou")("Spider")(" was here!"))
console.log(curried("Spider")("Tigrou")(" was also here!"))
console.log(curried("Tigrou", "Spider", " are in a boat... "))
console.log(curried(1)(2, 3))
Here's a full working solution for you (except the string spacing)
const build_sentence_n_params = 3;
function build_sentence(...args)
{
var i = 0
var s = ""
for (let arg of args)
{
if (i == 1)
{
i++
s += "(buddy of " + arg + ") "
}
else
{
s += arg + " "
i++
}
}
return s
}
// A generic n-parameter curry helper, that returns fn return value
// after n-parameters given, and continues currying with more parameters.
// Note that in this configuration, the caller would also need
// to know how many parameters to give before a value is returned.
function ncurry(fn, n)
{
// Note that we have to return an outer function here, rather than just
// returning `curry` function directly, so `params` is unique for each
// initial call to `curried`.
return function(...args) {
// Initial arguments (note: we can use this array without copy, since
// rest params will always be a new array)
const params = args;
// This function contains the return logic without having to duplicate it below
function next() {
// If we have all params, call the given function, otherwise
// return the curry function again for more parameters
return !n || params.length >= n ? fn.call(null, ...params) : curry;
}
// The outer function is only called once, but this curry
// function will be called for each additional time.
function curry(...args) {
// Accumulate additional arguments
params.push(...args)
return next();
};
return next();
};
}
function mycurry(build_sentence)
{
// Call the generic n-parameter curry helper to generate
// a specific curry function for our purposes.
return ncurry(build_sentence, build_sentence_n_params);
}
const curried = mycurry(build_sentence);
console.log(curried("Tigrou")("Spider")(" was here!"))
console.log(curried("Spider")("Tigrou")(" was also here!"))
console.log(curried("Tigrou", "Spider", " are in a boat... "))
console.log(curried(1)(2, 3))
Your method invocations are quite confusing so I took the liberty to simplify your code.
If you run the following:
const curried = build_sentence("Tigrou", "Spider", " was here!");
console.log(curried);
You will get your desired output:
Tigrou (buddy of Spider) was here!
Why you are using the mycurry method is beyond my understanding.
When debugging your code, the sentence is already built on the first invocation, and what happens is that the subsequent invocations are not really invocations of the inner functions.
the main issue about our code is that !args is all the time false, as [] to boolean is also true.
you have to use !args.length. however you should add an extra call to your curried function usage like curried(1)(2, 3)().
the other approach is using comparison of curried function number of required params (build_sentence.length) and the number of params passed (args.length), but it's not working with spread scenario.
upd:
ex.1 - using Function.prototype.length property
const curry = fn =>
(...args) =>
fn.length <= args.length
? fn(...args)
: curry(fn.bind(this, ...args));
const func1 = (a, b, c) => `${a},${b},${c}`;
const func2 = (...args) => args.join(',');
console.log(curry(func1)(1,3)(4));
console.log(curry(func1)(1,3,4));
console.log(curry(func1)(1)(3)(4));
console.log(curry(func2)(1));
in this case currying will work fine for func1 (function that has enumerable number of arguments) because func1.length = 3. however for func2 - func2.length = 0, so (curry(func1)) will be executed after first call.
ex.2 - using number of arguments passed
const curry = fn =>
(...args) =>
!args.length
? fn()
: curry(fn.bind(this, ...args));
const func = (...args) => args.join(',');
console.log(curry(func)(1)(2,3,4)(5)());
in this case function currying will only return result of fn executing, when called with no arguments. however it will handle innumerable arguments of curried function properly.
I am creating an app using React, Redux.
Among them, I am making a Redux middleware,
There is a part that I do not understand.
Here is the code:
const loggerMiddleware = store => next => action => {
console.log('currentState', store.getState());
console.log('action', action);
const result = next(action);
console.log(', store.getState());
console.log('\n');
return result;
}
export default loggerMiddleware;
What is this arrow function => => =>?
It does not make sense that the arrow function continues.
What does that mean?
The code below:
const loggerMiddleware = store => next => action => {
var result = /* .. */
return result;
}
is the equivalent of:
const loggerMiddleware = function(store) {
return function(next) {
return function(action) {
return result;
}
}
}
This is a technique (called currying) that replaces a single function which takes some arguments with multiple functions each taking a part of those arguments, for example:
const f1 = (x, b) => x + b;
const f2 = x => b => x + b;
const f1Result = f1(1, 2);
// we can construct f2's result in multiple steps if we want because it returns a function, this can be helpful.
let f2Result = f2(1);
f2Result = f2Result(2);
console.log('f1Result', f1Result);
console.log('f2Result', f2Result);
You can also read this for more insight of the rationale behind this decision, mainly:
Sometimes we want to associate some local state with store and next
Javascript arrow function is the replacement of 8 characters 'function' keyword. you don't need to write return within your function when you are using arrow function.
As per Javascript best practices try to use when you are making service calls. It is used as function keyword short hand.
For more on this see a good sample on this link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
I wrote a function:
function add(){
let arr = [];
arr = arr.concat(Array.prototype.slice.apply(arguments))
let fun = function(){
arr = arr.concat(Array.prototype.slice.apply(arguments))
return fun
}
fun.toString = function(){
console.log(222)
return arr.reduce(function(total, num){
return total+num
}, 0)
}
return fun
}
console.log(add(1,2)(2,3)(3))
This is in Chrome:
enter image description here
Two questions:
In first line, why is 'f 11' ,not '11'?
Why output 'f 11' firstly, not '222', I think the type conversion should execute firstly, and then output computed result on console.
Another strange thing, it is the result in Firefox with same codes:
enter image description here
And the result in node environment:
enter image description here
I do not understand why, it seems in FF and node, has not executed the computed operation.
Please help me...Thanks so much!
At first you can beautify the whole code a bit:
function add(..arr){
function fun(...args){
arr.push(...args);
return fun
}
fun.toString = function(){
return arr.reduce((total, num) => total + num)
};
return fun;
}
And as you noticed correctly, logging a function is completely up to the environment. Firefox and Node return the code of the function, while Chrome does sth like:
out( "f" + add.toString())
so our toString function gets called and something is logged. To have a consistent behaviour between the different environments we could call toString explicitly:
console.log(add(1)(2)(3).toString());
This can be inferred:
console.log("" + add(1)(2));
If what you want is add that is both variadic and curried (which I still think is weird), just do this:
const add = (...args) => {
let accum = args;
let f = (...fargs) => {
if (!fargs.length) {
return accum.reduce((a, b) => { return a + b; }, 0);
} else {
accum = accum.concat(fargs);
return f;
}
};
return f;
};
add(1,2,3)(); // 6
add(1)(2,3)(); // 6
add()(); // 0
Now you just call the returned function with no arguments to get the value out. You could toy with it to make it more performant (e.g. by using .push in a loop instead of .concat) but this should work.
I know that the purpose of memoize is to cache values so code can be run faster by not having to re-calculate the same answer everytime. My issue stems from returning a function (i think). The google chrome debugger isn't that useful for me here because everytime I try to run this memoize function, it just goes from the argus variable (on line 4 i believe) all the way down to the semi-colon. Furthermore, result always returns an empty object instead of storing a value in result.
I start by defining a function:
function add(a,b){
return a+b;
}
This is my attempt at the memoize function:
_.memoize = function(func) {
var result = {};
var flag = 0;
var argus = Array.prototype.slice.call(arguments)
return function() {
if(result[key] === arguments){
flag = 1
}
else if(flag = 0){
result[argus] = func.apply(this, argus);
}
return result[argus];
};
};
I'd call memoize by doing _.memoize(add(2,5)) but the result doesn't get stored in the result object.
Am I even close to getting this memoize function working properly? Any guidance you guys can give here would be appreciated.
The biggest point you're missing is that _.memoize is called on the function first, and it returns a new function. You are calling it on the result of a function call (which is the number 7 in this case).
In order to get it to work, you need to rearrange a few things.
Also note that it's not wise to try to use an array itself as the index to an object. One approach to get around that would be to convert the arguments array to JSON and use that as the index on the results object:
function add(a, b) {
console.log('Called add(' + a + ', ' + b + ')');
return a + b;
}
var _ = {};
_.memoize = function(func) {
var results = {};
return function() {
var args = Array.prototype.slice.call(arguments);
var key = JSON.stringify(args);
if (!(key in results)) {
results[key] = func.apply(this, args);
}
return results[key];
};
};
var madd = _.memoize(add);
console.log(madd(2, 4));
console.log(madd(9, 7));
console.log(madd(2, 4));