Rather than having the following 2 string functions and calling them both
removeTrailingSlash = (site) => site.replace(/\/$/, "");
getLastPartOfURL = (url) => url.substr(url.lastIndexOf('/') + 1);
I was hoping to be able to combine them into one high-order function definition
removeTrailingSlash = (site) => site.replace(/\/$/, "");
getLastPartOfURL = site => removeTrailingSlash => url => url.substr(url.lastIndexOf('/') + 1);
So I guess I am unclear how i can use arrow functions to do this or if there is a more elegant approach. Thanks.
A higher order function is a function that takes a function as an argument and/or returns a function.
This answer assumes you want to understand higher-order functions more (hence the title) and are not just looking for a better way to get the last part of a path (because this probably isn't it).
In your second example:
getLastPartOfURL = site => removeTrailingSlash => url => url.substr(url.lastIndexOf('/') + 1);
I read that getLastPartOfURL will be a function takes an argument site and returns a function that takes and argument removeTrailingSlash that returns a function that takes an argument url and then returns a substring of that url. Notice, that most of the arguments you passed in to these function (site, removeTrailingSlash) were not used.
For an arrangement like this, you can instead pass actual functions into those arguments and then compose the functions at the end for your final result.
For example:
//define a few simple functions
const removeTrailingSlash = (url) => url.replace(/\/$/, "");
const getLast = (url) => url.substr(url.lastIndexOf('/') +1 )
// define a higher order function that expects functions as arguments and composes them
const getLastPartOfURL = removeTrailingSlashFN => getLastFN => url => getLastFN(removeTrailingSlash(url))
// call it by passing in functions and url:
let result = getLastPartOfURL(removeTrailingSlash)(getLast)("http://www.example.com/test/")
console.log(result)
/* Notice that this arrangement allows you to make function partials! */
let partial = getLastPartOfURL(removeTrailingSlash)(getLast)
// now you only need to pass in url
console.log(partial("http://www.example.com/foo/"))
console.log(partial("http://www.example.com/bar/"))
There are a lot of other patterns, but hopefully this helps.
You already have a decent answer about higher-order functions, but I think the concept you might actually be looking for is function composition. Composition lets you define a new function that is the result of passing the result of one function into the input of another, like this:
const compose = (f, g) => x => f(g(x));
// Your original functions
const removeTrailingSlash = url => url.replace(/\/$/, "");
const getLast = url => url.substr(url.lastIndexOf('/') + 1);
const both = compose(getLast, removeTrailingSlash);
console.log(both('http://www.example.com/foo/'));
console.log(both('http://www.example.com/bar/'));
// You can even do another composition for logging
const logBoth = compose(console.log, both);
logBoth('http://www.example.com/foo/');
logBoth('http://www.example.com/bar/');
Note in this particular case, it is compose that is actually the higher order function. It takes two functions f and g as parameters and returns a new function as a result. The new combined function, both, isn't itself considered a higher-order function, even though it was created using one. It takes a string as a parameter and returns a string.
Also note that while you can define compose yourself as I did above, it is general purpose enough to be already included in libraries like Ramda.
I'm assuming that you're expecting to get an output of bar from an input of something like https://google.com/foo/bar/.
If that is the case then I recommend something like this.
url.split('/').filter(Boolean).pop();
This will split up your url into an array based on where the slashes are (in the example case it will be ['https:', '', 'google.com', 'foo', 'bar', '']), then it will filter out all of the empty strings, and then return the last item in the array (bar)
If you really want them to be different functions then I recommend something like Method chaining so you'll be able to do something like:
I am guessing you need a function that gets the last part of the url that ends with /.
const getLastPart = url => url.match(/\/(\w*)\/$/)[1];
const p = getLastPart('part1/part2/part3/');
console.log(p);
I suspect1 you just want getLastPartOfURL to call removeTrailingSlash before it returns:
const removeTrailingSlash = (url) => url.replace(/\/$/, '');
const getLastPartOfURL = (url) => {
const noTrailing = removeTrailingSlash(url); // call removeTrailingSlash
return noTrailing.substr(noTrailing.lastIndexOf('/') + 1);
};
const tests = [
'http://www.example.com',
'www.example.com/foo',
'http://www.example.com/foo/bar',
'http://www.example.com/foo/bar/',
'www.example.com/foo/index.html',
];
console.log(JSON.stringify(tests.map(getLastPartOfURL)));
1: A Higher-Order Function is a function that takes a function as a parameter, or returns a function as its output.
Related
I have an exercise where I have to give three arguments: function and two numbers.
The function which I give has to be activated (each) after x miliseconds for y miliseconds.
I wanted to make helper like this:
function helper(string) {
console.log("Printing string which was given: " + string)
}
but when I do it like this and I try to enable my function ex1_4(helper("some string"), 500,5000) I get an error that Callback must be a function
What am I doing wrong?
function ex1_4(func, x,y) {
const resFunction = setInterval((func), x)
const stop = setTimeout(() => {clearInterval(resFunction)}, y)
}
function helper(string) {
console.log("Printing string which was given: " + string)
}
ex1_4(helper("some string"),500,5000)
helper("some string")
Is a function call which returns a value, in your case it is undefined. If you want to make it into a callback, you need to wrap it in a function like so:
() => helper(“some string”)
In your code:
ex1_4(() => helper("some string"),500,5000)
When you add helper("some string"), you're actually executing the method, instead of sending the method to ex1_4. You should type something like ...
ex1_4(helper,500,5000) // no parenthesis
... just like you did with setInterval((func), x).
However, you want to add parameters to helper, and in this case, you can use bind. You should really learn about bind(), call(), and apply().
ex1_4(helper.bind(null, "some string"),500,5000)
function ex1_4(func, x,y) {
const resFunction = setInterval((func), x)
const stop = setTimeout(() => {clearInterval(resFunction)}, y)
}
function helper(string) {
console.log("Printing string which was given: " + string)
}
ex1_4(helper.bind(null, "some string"),500,5000)
I saw in one tutorial this code snippet:
const myFunction = () => {
return function (caller) {
caller(firstFuctnion());
caller(secondFunction());
};
};
Could you please tell me how it works once I call it like:
myFunction()
How come that I don’t get an error when the caller argument is actually not defined?
On the other hand, if I omit it and write the code like this:
const myFunction = () => {
return function () {
firstFuctnion();
secondFunction();
};
};
those two functions firstFuction() and secondFunction() aren’t executed. So, how exactly does that caller — or however it’s called — work?
For those of you who might want to see the whole functioning code:
const redux = require("redux");
const thunkMiddleware = require("redux-thunk").default;
const axios = require("axios");
const createStore = redux.createStore;
const applyMiddleware = redux.applyMiddleware;
const initialState = {
loading: false,
users: [],
error: "",
};
const FETCH_USERS_REQUEST = "FETCH_USERS_REQUEST";
const FETCH_USERS_SUCCESS = "FETCH_USERS_SUCCESS";
const FETCH_USERS_FAILURE = "FETCH_USERS_FAILURE";
const fetchUsersRequest = () => {
return {
type: FETCH_USERS_REQUEST,
};
};
const fetchUsersSuccess = (users) => {
return {
type: FETCH_USERS_SUCCESS,
payload: users,
};
};
const fetchUsersFailure = (error) => {
return {
type: FETCH_USERS_FAILURE,
payload: error,
};
};
const fetchUsers = () => {
return function (dispatch) {
dispatch(fetchUsersRequest());
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((response) => {
// response.data is the users
const users = response.data.map((user) => user.id);
dispatch(fetchUsersSuccess(users));
})
.catch((error) => {
// error.message is the error message
dispatch(fetchUsersFailure(error.message));
});
};
};
const reducer = (state = initialState, action) => {
console.log(action.type);
switch (action.type) {
case FETCH_USERS_REQUEST:
return {
...state,
loading: true,
};
case FETCH_USERS_SUCCESS:
return {
loading: false,
users: action.payload,
error: "",
};
case FETCH_USERS_FAILURE:
return {
loading: false,
users: [],
error: action.payload,
};
}
};
const store = createStore(reducer, applyMiddleware(thunkMiddleware));
store.subscribe(() => {
console.log(store.getState());
});
store.dispatch(fetchUsers());
I don't get this part. What that dispatch actually does. It is nowhere passed as an argument and it is not defined anywhere what it is. Is it function? I could write whatever there instead.
const fetchUsers = () => {
return function (dispatch) {
dispatch(fetchUsersRequest());
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((response) => {
// response.data is the users
const users = response.data.map((user) => user.id);
dispatch(fetchUsersSuccess(users));
})
.catch((error) => {
// error.message is the error message
dispatch(fetchUsersFailure(error.message));
});
};
};
Let’s consider a simplified version of this code.
Before you added some important context to your question (the fact that myFunction() is actually being used, and how it’s used), I wasn’t quite sure where your confusion was, so this answer starts with a general explanation of callbacks, higher-order functions, and currying.
First, let’s turn the function into an arrow function, so the code is more straight-forward to read.
There are differences between them, but let’s ignore them for now.
Let’s also rename myFunction to outer, so we know which function we’re talking about.
const outer = () => {
return (caller) => {
caller(something);
};
};
outer is a function.
outer() is also a function; that means, the return value of the function outer is, itself, a function.
Since outer is a function that returns a function, this makes outer a higher-order function (HOF) (according to one of the two definitions of HOFs)1.
To be explicit, you can reference the returned function by using another variable:
const inner = outer();
How come that I don’t get an error when the caller argument is actually not defined?
That’s a strange question to ask; when outer() is called, it doesn’t touch on caller yet.
Only calling inner does.
Ask yourself this: why do you not get an error for a and b not being defined here?2
const sum = (a, b) => a + b;
sum;
That’s right: sum isn’t even called!
Just like outer() isn’t even called.
Even one step further, this won’t throw an error even if somethingUndefined isn’t defined anywhere and cannot be set anywhere.
(But you will get linter warnings.)
const someFunction = () => somethingUndefined;
someFunction;
Why do you not get an error here, in this common example of HOFs, despite b not being defined at the point where add(5) is assigned to addFive?
const add = (a) => {
return (b) => a + b;
};
// Or more simply:
// const add = (a) => (b) => a + b;
const addFive = add(5);
console.log(addFive(3)); // Pints 8.
Because the function that needs b, i.e. addFive, has not been called yet.
If you want to force an error due to caller not being defined, you’d have to call the function that actually needs caller defined. The function in question is outer()! You call it, like any other function, with (): outer()(). Now you get a TypeError because caller isn’t a function.
This “double call” is called currying.
The code can also be rewritten like this.
The only difference is that inner is now also accessible in the outer scope where outer is.
See What is the scope of variables in JavaScript?.
const inner = (caller) => {
caller(something);
};
const outer = () => inner;
inner takes the role of the returned function (outer()).
It takes a function as an argument and calls it with something as an argument.
outer is just a function that returns the function inner and nothing else.
It does not call it, it doesn’t touch on caller, it has nothing to do with something.
outer() and inner are identical.
On the other hand, if I omit it and write the code [without caller], those two functions firstFuction() and secondFunction() aren’t executed. So, how exactly does that caller — or however it’s called — work?
First, let’s fix the semantics: firstFuction() and secondFunction() are function calls.
Whether they are functions or not, depends on what firstFuction and secondFunction return.
firstFuction and secondFunction are functions (at least the code implies that they are).
More specifically, consider alert:
alert is a function; you can call it like alert().
alert() is not a function; you cannot call it like alert()().
caller is a callback function.
If you omit caller from the code, then myFunction()() would be the proper call that doesn’t throw an error and simply calls firstFuction and secondFunction.
But the point of the callback is to pass the results of firstFuction and secondFunction to the function caller.
You have to provide that function yourself, e.g. the alert function.
myFunction()(alert) calls the inner function, passing alert to it.
The inner function calls firstFuction and secondFunction and passes their results to the caller, which we specified to be alert.
Could you please tell me how it works once I call it like myFunction()?
Quite simply, nothing happens here.
myFunction returns a function, and that’s it; that function isn’t used further, so it is discarded.
There is a key aspect of higher-order functions that isn’t demonstrated in this code: encapsulating values.
Consider this code:
const add = (a) => {
let count = 0;
return (b) => {
++count;
console.log(`The function to add ${a} to something else has been called ${count} time(s).`);
return a + b
};
};
add and b work similarly to myFunction and caller from before, but now, the outer function also needs an argument, so add() won’t help.
add(5) calls the add function and sets argument a to 5.
Further, add(5)(3) calls the inner, returned function, sets b to 3 and returns 8.
But there’s also some state inside add in the form of a variable called count.
const addFive = add(5);
console.log(addFive(3)); // Prints 8.
// But also logs: "The function to add 5 to something else has been called 1 time(s)."
console.log(addFive(10)); // Prints 15.
// But also logs: "The function to add 5 to something else has been called 2 time(s)."
count is only accessible inside outer (including any function inside of it); it is “encapsulated”.
This is a common way to hide some state that should only be accessible inside a specific function.
a is actually also encapsulated inside add(…); a and count have the same scope and aren’t that different from each other, just that a can be set as an argument when calling add whereas count cannot.
You’ve then added more context, where the call looks more like this:
someOtherFunction(myFunction())
This is different from the situation before where you just wrote the call like myFunction().
Now, the result is not discarded, as it is fed into someOtherFunction (in the original code: store.dispatch).
[caller] is nowhere passed as an argument and it is not defined anywhere.
But now it is the job of someOtherFunction to call myFunction() with the appropriate callback function as an argument.
Now, you don’t pass the function yourself; instead, someOtherFunction does it for you.
Compare this to Where do the parameters in a JavaScript callback function come from?.
If you go back to the sum example function from earlier, then either you pass the arguments yourself:
sum(1, 2);
or some library or framework does it for you:
// Library code
const doTheRightThing = (callback) => callback(1, 2);
// Your code
doTheRightThing(sum);
or a built-in (or host-defined) function does it for you:
[ 1, 2, 3 ].reduce(sum, 0);
It doesn’t matter where these parameters come from or where the function is called from.
But it is called, and it is called with the right arguments somewhere.
1: The two definitions of a higher-order function are
a function that returns a function, or
a function that takes another function as an argument.
outer fits the first definition.
outer() (independently and coincidentally) fits the second definition.
2: Okay, granted, sum() would also not throw an error, but a and b would, nonetheless, be undefined, each. undefined + undefined has semantics that don’t result in an error, but hopefully you get the point: in your original code, myFunction()() would throw an error only because undefined(firstFunction()) isn’t possible. The culprit is the same: caller is undefined.
Functions are treated like any other values, meaning they can be returned from functions.
Calling myFunction will simply return the inner function, which will require a parameter caller to be passed to it when it itself is called.
The inner function will remember any arguments that were passed to it's enclosing function.
An example I use to understand this concept is that of a "multiplier factory" function
const answer = function() {
console.log("The answer is: ");
}
const multiplier = function(factor) {
return function(n){
answer();
console.log( n * factor);
};
}
const twice = multiplier(2);
const triple = multiplier(3);
twice(4); // The answer is: 8
triple(5); // The answer is: 15
In the code above twice and triple are essentially the following
const twice = function(n) {
console.log("The answer is: ");
console.log(n * 2);
}
const triple = function(n) {
console.log("The answer is: ");
console.log(n * 3);
}
twice(4); // The answer is: 8
triple(5); // The answer is: 15
To understand more about these concepts, I suggest reading up on "Higher Order Functions" and "Closures" in Javascript
I think you haven't printed the whole snipet. because, there is no definition to firstFunction() and secondFunction() inside myFunction().
to answer your question, if you want to call the function defined in myFunction(), you need to assign the value to a new variable as it is returning the function. then simple make the function call.
const myFunctionResult = myFunction();
myFunctionResult(someOtherCallerFunction);
but note this will throw an error for the reason mentioned above.
I am new to JS and was learning promises. The code excerpt I want to show is this
promisedFunction.then(data=>console.log(data))
or simply
promisedFunction.then(console.log)
which is equivalent of the former code excerpt. The question is how is that possible to just use then(console.log) instead of then(data=>console.log(data))? Does it mean that we can omit the passed-from-promise data in thenable callback?
data=>console.log(data) is a function that takes a parameter and calls a method with the passed in argument.
If you pass console.log it will execute the same method and still pass the same argument.
In effect you are dropping the extra function call - slightly more abstractly, imagine this:
//some function `f`
const f = x => x + 1;
//different function `g` that just forwards the call to `f`:
const g = x => f(x);
console.log(g(41)); //42
The definition of g is just a function that all it does is call f. Which has exactly the same effect as the f function. So, we can just re-write it as:
//some function `f`
const f = x => x + 1;
//different function `g` that just forwards the call to `f`:
const g = f;
console.log(g(41)); //42
and get exactly the same effect.
In Lambda Calculus, this removal of an essentially empty "wrapper function" is called Eta reduction.
Therefore, yes, both .then(data => console.log(data)) and .then(console.log) do exactly the same, you're performing the same sort of conversion where you're taking out a dummy forwarding function.
However, that's not always an option. For example, if removing the forwarding function will end up calling the target with more parameters, you can get different behaviour. An infamous example is parseInt when used in .map:
const arrayOfString = ["1", "2", "3"];
const arrayOfIntegers1 = arrayOfString.map(parseInt);
const arrayOfIntegers2 = arrayOfString.map(x => parseInt(x));
console.log("arrayOfIntegers1", arrayOfIntegers1);
console.log("arrayOfIntegers2", arrayOfIntegers2);
The issue is that Array#map calls the callback with three parameters - the item, the index, and the array. And parseInt has an optional second parameter - if passed in, it changes how the number is parsed. So you get NaN.
The easiest way to observe this is with console.log:
const arrayOfString = ["1", "2", "3"];
console.log(" --- using just `console.log` as callback ---");
arrayOfString.map(console.log);
console.log(" --- using just `x => console.log(x)` as callback ---");
const arrayOfIntegers2 = arrayOfString.map(x => console.log(x));
So, dropping the intermediate function works as long as it has the same arity as what it will be called with and what the next function will be called with.
data => console.log(data) is a function which takes in data and then calls the function console.log with data as its argument. So, it's a function which gets given data and then it gives that exact same data argument to the console.log function.
As you know console.log is a function, so, you can place console.log instead of your arrow function. This way, it will be called with the data argument and any other arguments natively passed into .then()'s onFulfilled callback (in this case it only gets given the resolved value of the promise).
Take the following example below. bar gets given "hello", which it gives to foo, foo accepts "hello" and returns "hello" back to where it was called, so, bar ends up returning "hello":
const foo = x => x;
const bar = x => foo(x);
console.log(bar("hello"));
In the above example, bar acts somewhat like a middle-man, as all it does is pass x to foo. This middle-step can be removed, by straight-up assigning bar to foo. This way, when we call bar(), we are executing the code defined within the function foo. This is the same idea that allows you to remove the need to explicitly defined your arrow function in .then():
const foo = x => x;
const bar = foo;
console.log(bar("hello"));
This style of coding is known as point-free style code and, in this case, is achieved by eta-reduction.
The return value of promise or the "resolved value" is the input to callback passed in then.
This behavior is not specific to promise but even [1,2,3].forEach(console.log) behaves the same where the 3 arguments of forEach are passed to console log. Thus you get ,
1 0 Array(3) [ 1, 2, 3 ]
2 1 Array(3) [ 1, 2, 3 ]
3 2 Array(3) [ 1, 2, 3 ]
promisedFunction.then expects a function to which will receive the data as a parameter.
in the case of data=>console.log(data) is an array function equal to:
function(data) {
console.log(data);
}
and console.log is also a function which prints in console what receives as a parameter.
That's why console.log works.
If you had:
var print = function(data) {
console.log(data);
}
promisedFunction.then(print) would also work.
See this working example that will resolve after 2 secs:
const doSomething = function(){
return new Promise((resolve, reject) => {
let wait = setTimeout(() => {
resolve('Promise resolved!');
}, 2000)
})
};
var print = function(data) {
console.log(data);
}
doSomething().then(print)
Really sorry if the title does not make sense. Not sure how to make my question short
What I am wondering is,
I have a recursive function, well doesn't have to be recursive function just when I am doing this function, I wondered if it can be reused in a more flexiable way.
my function looks like this runAxios(ele, api) is the function I wonder if can be reused
const ct = (arr, num, res) => {
const promises = [];
for(let i = 0; i < num; i++){
const ele = arr.shift(); // take out 1st array, literally take out
if(ele){
promises.push(
runAxios(ele, api) // this is the function I am wondering if can be reused
)
}
}
Promise.all.......
};
if runAxios(ele, api) can be anything then I believe this ct can be a lot more flexiable?
I am wondering if it could it something like
const ct = (arr, num, res, fx) => {
const promises = [];
for loop......
if(ele){
promises.push(
fx // this is then passed as any other function other than just a fixed `axios function` that I wrote
)
}
}
Promise.all........
};
when I first tried it, I realized this will not work because runAxios's first parameter is done inside the loop which means the variable does not exist yet until it's inside the function itself.
Just being curious if there is such way to easily do it that I just don't know how or it's actually not possible?
Thanks in advance for any advices.
You were very close with your approach. It should look something like this:
const someFunction = (x) => new Promise((resolve) => resolve(x));
const ct = (arr, fn) => {
const promises = arr.filter(x => x).map(x => fn(x));
Promise.all(promises).then(x => console.log(x));
};
ct([1, 2, 3], someFunction);
(I also took the liberty to replace your loop with a more compact approach.)
Of course it can be done. You just have to call the function passed with the required paramemeters. You will calculate the ele parameter and then pass it to the function. A generic example to see the way it works is shown below:
const functionToBeCalled = (parameter1, parameter2) => {
console.log(parameter1 + parameter2);
}
const ct = (fx) => {
//..code
let ele = 1;
fx(ele, 2);
//..code
};
ct(functionToBeCalled);
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