This is one of those job interview tests on HackerRank that I am embarrassed to say I didn't complete within the allotted 20 minutes, and it's driving me nuts. Basically, you're given the following:
function myList() {
// write code here
}
function main() {
// You can't edit this function. This is just pseudo, from what I can remember
const obj = myList();
if (operation === "add")
obj.add(item);
else if (operation === "remove")
obj.remove(item);
else
obj.getList();
// Some more stuff here
}
So my first train of thought was to write the following inside myList():
let objList = [];
function add(item) {
objList.add(item)
}
// etc., etc.
return {add, remove, getList};
Needless to say, the above didn't work, with the error: obj.add is not a function, in the main function.
I tried experimenting with this and the returns (only returning add, with or without {}), but didn't really get anywhere. What could I have done to get this working?
As the answer from Attersson already suggested, you could use a closure inside the myList function. This would allow to only expose the three methods add, remove and getList while the original list cannot be accessed. Here is an example:
function myList() {
return (() => {
const obj = {itemList: []}
const add = (item) => obj.itemList.push(item)
const remove = (item) => obj.itemList = obj.itemList.filter(i => i !== item)
const getList = () => obj.itemList
return {add, remove, getList}
})()
}
For obj, inside myList() you could have run a closure, that is a self invoking function returning, in this case, an object with your k:v exports, but with private access to the context of the now expired anonymous caller. With "const add = function" etc statements you can define values for your exports, while the objList goes in the private context.
Related
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've made a promise based function which crawls up a hierarchy until it reaches the top, and resolves with an object containing the structure. My only gripe with the code is that I modify variables outside the function body, meaning that it is not a pure function. I've looked into JavaScript closures, and I fully grasp trivial uses of them. But I'm struggling to figure out how/if they can help make my function pure. My attempts at making a closure so far have only overwritten the variables, not modified them. Here is the code in question using global variables:
/* I want to move these variables inside function body to purify 'getPriorRows'*/
let priorRows = {}, level = 0;
const getPriorRows = id => new Promise(resolve => {
fetch(`/api/org/${id}`).then(result => {
/* global varaiables are modified here */
priorRows[level++] = result;
if (result.parentID) resolve(getPriorRows(result.parentID));
else resolve(priorRows);
});
});
getPriorRows('123432').then(result => console.log(result));
Any input on the matter is greatly appreciated.
Pass the values as arguments:
function getPriorRows(id, priorRows = {}, level = 0) {
return fetch(`/api/org/${id}`).then(result => {
/* global varaiables are modified here */
priorRows[level] = result;
if (result.parentID) return getPriorRows(result.parentID, priorRows, level+1);
else return priorRows;
});
}
getPriorRows('123432').then(result => console.log(result));
You can use either default parameters or a wrapper function, you don't even need a closure:
function getAll(id) { return getPriorRows(id, {}, 0); }
Also the I removed the Promise constructor antipattern.
You should be able to enclose the entire function and its "external" variables in a new function:
function getPriorRows(id) {
let priorRows = {}, level = 0;
const getNext = id => new Promise(
...
);
return getNext(id);
}
That said, your creation of an explicit new Promise in each iteration is a Promise anti-pattern:
function getPriorRows(id) {
let priorRows = {}, level = 0;
const getNext = id => fetch(`/api/org/${id}`).then(result => {
priorRows[level++] = result
if (result.parentID) {
return getNext(result.parentID));
} else {
return priorRows;
}
});
return getNext(id);
}
Either way, the advantage of wrapping the state like this is that you could now have multiple calls to getPriorRows proceeding in parallel without interfering with each other.
EDIT second code edited to fix a copy&paste error with the recursion - you must call the inner function recursively, not the outer one.
As soon as I've found out about JavaScript => syntax I run through my whole code and replaced every function keyword with =>. I guess it felt, well, cool. But then I figured that it actually isn't. So I replaced every => back to function keyword, and I run across a strange error:
const $ = (id) => document.getElementById(id);
class Car {
constructor(id, name, color, price) {
this.id = id;
this.name = name;
this.color = color;
this.price = price;
}
body() {
return(`
<div id="${this.id}">
<img src="${this.id}Img.png">
</div>
`);
}
tooltip() {
return(`
<div id="tooltip">
<p>The ${this.name} we offer is painted ${this.color}, and the price would be ${this.price} USD</p>
</div>
`);
}
generate() {
$('root').insertAdjacentHTML('beforeend', this.body());
// Error occurred here:
$(this.id + 'Img').onclick = function() {
$(this.id).insertAdjacentHTML('beforeend', this.tooltip());
}
// However, arrow function does the trick:
$(this.id + 'Img').onclick = () => {
$(this.id).insertAdjacentHTML('beforeend', this.tooltip());
}
}
}
const mercedes = new Car('mercedes', 'Mercedes', 'blue', 15000);
mercedes.generate();
Now, if I call some function that belongs to the global Object (I guess that's how it's called), in this example, onclick, I have to bind Cars this to it as well? .bind(this), or => function. Is this the reason arrow function was invented? Because, this inside onclick function actually refers to that global Object, or something...
Another example would be the first line of code I provided. Should I use arrow functions for returning 1 line of code, or should I wrap it like:
function $(id) {
return document.getElementById(id);
}
and really use arrow functions when they are absolutely mandatory? I figured if it's just 1 line of code that returns something, and since arrow functions don't need {} and return keyword, it would be OK to use them in that case. For example:
function main() {
const mercedes = new Car('mercedes', 'Mercedes', 'blue', 15000);
mercedes.generate();
}
window.onload = () => main();
Another example where I found them to be kind of helpful, is with callbacks. NodeJS code can get pretty messy, so omitting the function keyword can make it cleaner. However, having a function keyword on the other hand can make a lot of nested callbacks less confusing...
// Shorter syntax:
socket.on('listenEvent', (data) => {
// do something with data
});
// Less confusing, but longer syntax:
socket.on('listenEvent', function(data) {
// do something with data
});
So, if I wanted my first example to work, i would have to do:
$(this.id + 'Img').onclick = function() {
$(this.id).insertAdjacentHTML('beforeend', this.tooltip());
}.bind(this);
So, looking at it again, if that is what arrow function translates to, doing something like
const $ = function(id) {
return document.getElementById(id);
}.bind(this);
Kind of makes no sense... At the very end, I know that this question mostly comes down to personal preference. Is the class example I provided the only place where anyone would absolutely need to use =>, or function with bind? So opinions aside, is my understanding of arrows OK, or am I missing a point?
Thanks!
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'm trying to debounce a save function that takes the object to be saved as a parameter for an auto-save that fires on keystroke. The debounce stops the save from happening until the user stops typing, or at least that's the idea. Something like:
var save = _.debounce(function(obj) {
...
}, delay);
Where this falls apart is if I try to save two objects in quick succession. Because the debounce doesn't take the passed in object into account, only the second call to save will fire and only one object will be saved.
save(obj1);
save(obj2);
Will only save obj2, for example.
I could make obj an instance of a class that has its own save method that takes care of debouncing saves to just that object. Or keep a list of partial/curried functions somewhere, but I'm hoping there's a one stop solution out there. Something like:
var save = _.easySolution(function(obj) {
...
}, delay);
What I'm looking for the following string of saves to save each object, but only save each object once.
save(obj1);
save(obj2);
save(obj3);
save(obj2);
save(obj2);
save(obj3);
save(obj2);
save(obj1);
EDIT: Something like this, maybe, just not so convoluted, and something that doesn't mutate the obj with a __save function?
function save(obj) {
if(!obj.__save) {
obj.__save = _.debounce(_.partial(function(obj) {
...
}, obj), delay);
}
obj.__save();
}
You're going to want to create a debounced version of the function for each argument that get's passed. You can do this fairly easily using debounce(), memoize(), and wrap():
function save(obj) {
console.log('saving', obj.name);
}
const saveDebounced = _.wrap(
_.memoize(() => _.debounce(save), _.property('id')),
(getMemoizedFunc, obj) => getMemoizedFunc(obj)(obj)
)
saveDebounced({ id: 1, name: 'Jim' });
saveDebounced({ id: 2, name: 'Jane' });
saveDebounced({ id: 1, name: 'James' });
// → saving James
// → saving Jane
You can see that 'Jim' isn't saved because an object with the same ID is saved right after. The saveDebounced() function is broken down as follows.
The call to _memoize() is caching the debounced function based on some resolver function. In this example, we're simply basing it on the id property. So now we have a way to get the debounced version of save() for any given argument. This is the most important part, because debounce() has all kinds of internal state, and so we need a unique instance of this function for any argument that might get passed to save().
We're using wrap() to invoke the cached function (or creating it then caching it if it's the first call), and pass the function our object. The resulting saveDebounced() function has the exact same signature as save(). The difference is that saveDebounced() will debounce calls based on the argument.
Note: if you want to use this in a more generic way, you can use this helper function:
const debounceByParam = (targetFunc, resolver, ...debounceParams) =>
_.wrap(
_.memoize(
() => _.debounce(targetFunc, ...debounceParams),
resolver
),
(getMemoizedFunc, ...params) =>
getMemoizedFunc(...params)(...params)
)
// And use it like so
function save(obj) {
console.log('saving', obj.name);
}
const saveDebounced = debounceByParam(save, _.property('id'), 100)
Maybe something like:
var previouslySeen = {}
var save = _.debounce(function(obj) {
var key = JSON.stringify(obj);
if (!previouslySeen[key]) {
previouslySeen[key] = 1;
} else {
...
}
}, delay);
You can use internal object in closure for set/get debounced function.
In this example we check if debounced function with this args alredy saved in our memory object while call debounced function. If no - we create it.
const getDebouncedByType = (func, wait, options) => {
const memory = {};
return (...args) => {
// use first argument as a key
// its possible to use all args as a key - e.g JSON.stringify(args) or hash(args)
const [type] = args;
if (typeof memory[searchType] === 'function') {
return memory[searchType](...args);
}
memory[searchType] = debounce(func, wait, { ...options, leading: true }); // leading required for return promise
return memory[searchType](...args);
};
};
Original gist - https://gist.github.com/nzvtrk/1a444cdf6a86a5a6e6d6a34f0db19065