Instead of:
const fn = (ctx, a, ...rest) => {};
const fnCurried = (ctx) => (b) => (...rest) => fn(ctx, b, ...rest);
someFn("something", fnCurried(ctx));
I would like to be able to call "fn" at top level, so I thought maybe storing the context in another method would help, I have no idea how to go about doing this
const fnCurried = createCtx(ctx)
someFn("something", fnCurried(fn))
In your first example, someFn takes a second argument as a function of the form:
(b) => (...rest) => fn(ctx, b, ...rest);
In your second example, you want to keep this behaviour, this means calling fnCurried(fn) must return the above function. We can do this by writing:
const fnCurried = (fn) => (b) => (...rest) => fn(ctx, b, ...rest);
However, if we just use this, then we haven't supplied the context anywhere. That's where we can make another function called createCtx() that will return the above fnCurried function for us, while also closing over a supplied ctx:
const createCtx = ctx => fn => b => (...rest) => fn(ctx, b, ...rest);
const fnCurried = createCtx(ctx);
someFn("something", fnCurried(fn));
The createCtx function allows us to pass in the context, which then returns fnCurried for us, that can be passed into someFn once called
Related
I have an arrow function that looks like this (simplified):
const f = arg => { arg.toUpperCase(); };
But when I call it, I get undefined:
console.log(f("testing")); // undefined
Why?
Example:
const f = arg => { arg.toUpperCase(); };
console.log(f("testing"));
(Note: This is meant to be a clean, canonical dupetarget for the specific issue with arrow functions above.)
When you use the function body version of an arrow function (with {}), there is no implied return. You have to specify it. When you use the concise body (no {}), the result of the body expression is implicitly returned by the function.
So you would write that either with an explicit return:
const f = arg => { return arg.toUpperCase(); };
// Explicit return ^^^^^^
or with a concise body:
const f = arg => arg.toUpperCase();
Examples:
const f1 = arg => { return arg.toUpperCase(); };
console.log(f1("testing"));
const f2 = arg => arg.toUpperCase();
console.log(f2("testing"));
Slightly tangential, but speaking of {}: If you want the concise arrow's body expression to be an object initializer, put it in ():
const f = arg => ({prop: arg.toUpperCase()});
This question already has answers here:
Passing a function with parameters as a parameter?
(7 answers)
Closed 3 years ago.
I'm new to javascript and I was learning higher-order functions where I learned about passing functions as arguments to other functions. How can I pass a function with arguments to a function?
I want to pass the function's arguments when passing the function as parameter to the main function.
example :
function fubar(a,b,fun(c,d)){
//execute here
}
and not like this
function fubar(a,b,fun()){
fun(a,b)
}
Here's an example, just pass it like a regular argument, no specific syntax is required :)
// define the function argument like a regular argument
function fubar(a, b, fn){
// call that argument like a function
return fn(a, b);
}
// sample function
function add(c, d){
return c + d;
}
// pass the "add" function like a regular argument
let result = fubar(1, 2, add);
console.log(result);
You just need to pass the name of the function as the parameter, just like another variable.
for example :
foobar(5, 10, baz, ham);
function foobar(a, b, fn1, fn2){
...
fn1(); // call the baz function.
res = fn2(a,b); // calls ham func with a and b as parameter
console.log(res)
...
}
function baz(){
console.log("Inside the Baz function ");
}
function ham(s,t){
console.log(s, t);
return s+t;
}
If you're asking how to pass a function that will execute with some pre-determined arguments, you can do so using another function.
For example
const a = 'a'
const b = 'b'
const c = 'c'
const d = 'd'
function fubar(a, b, fn) {
console.info('func:', a, b, fn()) // executing "fn()" here
}
function fun(arg1, arg2) {
console.info('fun:', arg1, arg2)
return 'return value from fun' // just an example so you can see it in fubar()
}
fubar(a, b, () => fun(c, d))
Here, () => fun(c, d) is an self-contained, anonymous arrow function (or "lambda") that when called, will execute fun(c, d).
I'm brushing up on knowledge of Javascript and filling in some of the gaps.
for the memoize function, I get why it would console log the function as the memoizeSomeFunction const is just a function expression of someFunction being passed into memoize as an arg. what I can't seem to conceptualize is how the arg being passed into memoizeSomeFunction gets to the return part of the function. can someone elaborate?
const memoize = (fn) => {
console.log(fn);
return (arg) => {
console.log(arg)
}
}
const someFunction = (x = 0, y = 0) => {
return `x is {$x} y is ${y}`;
}
const memoizeSomeFunction = memoize(someFunction);
memoizeSomeFunction(1)
The memoize() function returns a function:
(...args) => {
console.log(...args)
}
That function collects its arguments into an array using the spread (...) syntax, and then un-collects them the same way in the console.log() call.
Thus when you call the function returned from memoize(), it simply logs the arguments passed.
To summarize:
Just one argument is passed to memoize(), your someFunction() function;
The memoize() function returns another function, and that function logs its arguments (and otherwise does nothing with someFunction());
The function source is logged when memoize() is called, and the argument list to the return value from that is logged whenever it is called. If you added another call to that returned function, you'd see those arguments logged separately.
// ES5 equivalent:
const memoize_es5 = function(fn) {
// fn is closured and can be used
// function returned, when it will be called we will have call arguments as well
return function () {
console.log(fn.apply(null, arguments));
}
}
const memoize = fn => (...args) => console.log(fn(...args));
const someFunction = (x = 0, y = 0) => {
return `x is ${x} y is ${y}`;
}
const memoizeSomeFunction = memoize(someFunction); // function received as result of memoize call
memoizeSomeFunction(1, 15); // pass arguments to that function function
// ...args in the arguments is a rest operator
// it just capture all rest arguments into an array:
((first, ...args) => console.log(first, args))(1, 2, 3)
// ...args in a function call is spread operator
// it spreads an array into parameter list:
console.log(...['spread', 'operator'])
This is the code
const func0 = (...args) => {
console.error('-------0-------');
console.error(args);
console.error(args.length);
func1(args);
}
const func1 = (...args) => {
console.error('-------1-------');
console.error(args);
console.error(args.length);
}
func0(1, 2, 3);
why the 2nd arg is different now, how to make it the same as 1st one ?
(...args) => in the parameter list transforms the arguments into an array named args. So when you call func1(args);, you're calling func1 with one argument, an argument that's an array (whereas func0 was called with three arguments).
If you wanted to call func1 with the three original arguments, use spread to transform the args array into a parameter list:
const func0 = (...args) => {
console.error('-------0-------');
console.error(args);
console.error(args.length);
func1(...args);
}
const func1 = (...args) => {
console.error('-------1-------');
console.error(args);
console.error(args.length);
}
func0(1,2,3);
Use Case:
I have a module of functions, each function is unit tested
I have a factory function that creates a stream of these functions that a third party library requires.
I would like to test that this factory function produces the correct stream. Using #cycle/Time, I am able to create the stream and assert on the stream.
I am able to assert that the functions appear on the stream in the correct order.
However, I am unable to assert on any function that is curried. How would one assert on curried functions?
Currently, I have a hack in place to JSON.stringify the functions and assert on their source.
To simplify the problem, I created a simple test suite so we aren't concerned with using #cycle/Time. It appears that curried functions are new instances of the function. Please see the code below.
I was wondering how would I be able to make the failing test pass? In this case I simulate the curried function by using bind. Is this possible?
const a = () => b
const b = () => {}
const c = (arg) => b.bind(null, arg)
const d = () => () => {}
describe("curried function test", function() {
it('should return a reference to b', () => {
expect(a()).toBe(b)
})
// This test fails because b.bind returns a new function.
it('should return a reference to a curried b', () => {
expect(c('foo')).toBe(b)
})
it('should create a new instance everytime', () => {
expect(d()).not.toBe(d())
})
});
I've setup a jsfiddle here.
"This test fails because b.bind returns a new function."
That's because what you get from c is the result from b.bind(null, arg), which isn't the same as b.
Otherwise, b.bind would be modifying b.
As mdn says:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
(source, emphasis mine)
Basically, c can't return a reference to b.
What you do have, is the resulting function's name:
const b = () => {};
const c = (arg) => b.bind(null, arg);
const e = c("foo");
console.log(e.name);
console.log(e.name === `bound ${b.name}`);
So, you could test that e.name equals "bound " + b.name.