declaring a function inside a function - javascript - javascript

I'm trying to build a middleware in redux to handle api requests.
While looking for inspiration I found this code:
redux api middleware
export default store => next => action => {
const callAsync = action[CALL_API];
if(typeof callAsync === 'undefined') {
return next(action);
}
.
.
.
function actionWith(data) {
const finalAction = assign({}, action, data);
delete finalAction[CALL_API];
return finalAction;
}
next(actionWith({ type: types.REQUEST }));
.
.
.
}
My question is: Why is the function actionWith decalared inside of the main function? Wouldn't it be more simple if the function was decalared outside and one will pass the function the action object also?
What is the benefit here?

Wouldn't it be more simple if the function was decalared outside and one will pass the function the action object also?
You are correct: you could have take actionWith outside of the outer function as long as you supplied action as an argument (actionWith(data, action)).
The functionality would be the same. However, the primary concern I have is maintainability: if you needed to modify the inner function to do something that required yet another variable from the outer function , you'd need to add another argument. If the duty of the function is closely tied to the internals of the outer function, leaving it in gives you ready access to the outer function's variables when you need to modify the code.
I would balance this concern of extra arguments (which generally favors keeping the function internal) against the usefulness of having the function available to other part of the code (which would favor taking it outside, for increased visibility). For example, if I had many outer functions that each had their own internal copies of actionWith, it would be better to have them to share a single version of actionWith.
That is, if I had
function outer1(action) {
function actionWith(data) { ... }
actionWith(thing);
}
function outer2(action) {
function actionWith(data) { ... }
actionWith(thing);
}
From a maintainability perspective, I would rather have
function actionWith(action, data) { ... }
function outer1(action) {
actionWith(action, thing);
}
function outer2(action) {
actionWith(action, thing);
}

Related

JavaScript anonymous function parameters and calling arrangement

In a tutorial related to React, which I am watching on YouTube:
https://www.youtube.com/watch?v=h3KeJRKYpj8
there was a piece of code that had the following (minute 13:40 in the video)
const setCounterWithValue = (value) => {
setCounter(value)
}
this function gets called from a button component in the following code:
<button onClick={() => setCounterWithValue(counter -1)}
The video tutorial suggested a way to shorten this function call and make it simpler.
So what he did was modifying the code to be as follows (minute 14:30 in the video):
const setCounterWithValue = value => () => {
setCounter(value)
}
which meant the button component became as follows:
<button onClick={setCounterWithValue(counter -1)}
So my problem here is that I was expecting the setCounterWithValue to be structured as the following:
const setCounterWithValue = () => (value) => {
setCounter(value)
}
so empty () then pass value which triggers the setCounter.
I would like to have some deep explanation and some resources (like articles and videos) that explain this in further details.
I disagree that its simpler... What they are doing is called currying. Its a shorthand way to create a function that returns a function. So a longhand form would look like this:
const setCounterWithValue = (value) => {
return function () {
setCounter(value)
}
}
Its probably easier to understand why the parameters go where they do when written in this form. When you call it inline you're calling the outer function <button onClick={setCounterWithValue(counter -1)} />. It then returns the a function that should be called when the button is clicked.
What they're doing there is called currying. In other words, it's a function that returns another function. Instead of firing it outright, they're taking the value of the first function's argument and utilizing it in the second function that is fired from the the click event. In this particular case I don't see it being any simpler as you're getting the same exact outcome but in this case your original function is just fired in the second function body. Nevertheless, more info on currying can be found here.
Calling the "simpler" function with setCounterWithValue(counter - 1) will return a function that, when executed, will pass through the counter value provided. The concept for this is called currying through the use of a closure. The function you "expected" wouldn't make much sense because you'd be calling it with a value, but that value never gets captured, so the function it returns is expecting a value parameter, which is not passed, it gets lost.
Here's the two examples:
Example 1:
const setCounterWithValue = value => () => {
setCounter(value)
}
When called with setCounterWithValue(42), it will return the following:
() => { setCounter(42) }
Example 2:
As opposed to what you said you expected, which would end up like the following:
const setCounterWithValue = () => (value) => {
setCounter(value)
}
Called with setCounterWithValue(42) would return the following:
(value) => { setCounter(value) }
Notice how the function being returned still expects a value to be provided. This is the difference between the two examples and why Example 1 would work, while this one wouldn't.
This is an example of currying, which you can use as an introduction to Higher Order Functions which are very common in the React ecosystem.
To break down what happens in this case and why your assumption on how the function should look is wrong, you first have to understand what JavaScript closures are.
Let's say we have this piece of code:
function foo() {
var bar = 5;
return function baz() {
console.log(bar);
}
}
foo(); // Returns a function. Nothing happens
foo()(); // The returned function is executed. Prints 5
Here we take advantage of a closure that is created on line 3. The function baz that we return from foo captures the context of its definition site (definition site = where the function is defined = in this case the foo function). So baz can be called from anywhere and still have access to the place in memory that bar points to.
The first invocation does nothing since the returned function is not called.
The second invocation calls the returned function therefore printing the number 5 to the console.
In order to understand your example snippet you can be more explicit in the function definition:
This:
const setCounterWithValue = value => () => {
setCounter(value)
}
can be rewritten like this:
function setCounterWithValue(value) {
return function() {
setCounter(value)
}
}
The instructor in the video just takes advantage of the implicit return feature of arrow functions
The code snippet just above will have the same result when used with your code. Hopefully, written like this, it makes more sense to you why there is no need for the anonymous function to have a value argument. It can access it via a closure.
As to why currying and high order functions are preferred by some JavaScript developers, the answer is way too long and opinionated, so I suggest you study the subject a bit more. A very interesting article can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
A bit harder to read but with a bunch of useful theory: https://eloquentjavascript.net/05_higher_order.html
It is easier to understand using function declaration instead of arrow functions. The tutorial suggests you refactor the function into a function factory:
function setCounterWithValue (value) {
return function () {
setCounter(value);
}
}
This means that calling the function above will return a function that requires no arguments:
let f = setCounterWithValue(1);
f(); // this sets counter to 1
Your suggested function instead returns a function that requires an argument:
function setCounterWithValue () {
return function (value) {
setCounter(value);
}
}
This means to set the value you will have to pass an argument:
let f = setCounterWithValue();
f(1); // set value to 1
The problem the refactor is trying to solve is that onclick functions are always called with an event object as the argument. When the button is clicked, the browser will call your function as:
setCounterWithValue(event);
You have no control over this. It is impossible to force the browser to call it any other way. Thus, ideally you want to pass into the onclick handler a function that ignores the event argument:
function setCounterWithValue (value) {
return function () {
setCounter(value);
}
}
let f = setCounterWithValue(counter -1); // this returns a function
// that ignores arguments
return <button onClick={f} />
most people would avoid using a temporary variable so:
<button onClick={setCounterWithValue(counter -1)} />
On the other hand, if you use your suggestion you would need to do:
{/* wrap in an anonymous function to ignore the event */}
<button onClick={() => setCounterWithValue(counter -1)} />

Why arrow function is not passing arguments?

I'm using angular w/ rxjs to observe user events on the interface. However, I'm having this really simple problem with passing arguments to a method in an arrow function. Here is the problem:
This is not working: searchterm is not being passed to this.searchFacilities
ngOnInit() {
this.searchTerm$.subscribe(searchterm => this.searchFacilities);/**Not working here**/
}
searchFacilities(term: string){
console.log(term);
this.facilityservice.searchFacilities(term)
.subscribe(results => this.facilityList = results);
}
But this works:
this.searchTerm$.subscribe(searchterm => { this.searchFacilities(searchterm); })
Clearly, I have other solutions that are pretty painless, but I really want to understand why my first approach is not working. Thanks!
Because the parameter is not passed directly to your function.
Example from the doc:
Rx.Observable.range(0, 3).subscribe(function (x) { console.log(x) });
The same example with an arrow function:
Rx.Observable.range(0, 3).subscribe(x => console.log(x));
Small clarification. The doc says you need to pass a callback to subscribe() and that this callback will receive the value(s) emitted by the observable.
We could write it like this:
const myCallBack = (val) => console.log(val);
Observable.range(0, 3).subscribe(myCallBack);
In your case you already have a callback, this.searchFacilities.
This means you can simply write:
this.searchTerm$.subscribe(this.searchFacilities);
Just like you can rewrite my original example to:
// Now `console.log` is the callback!
Observable.range(0, 3).subscribe(console.log);
In other words, the problem is not "Why arrow function is not passing arguments". The problem is that you created an arrow function whose body IS your callback, instead of just using your callback directly.
The expanded version of your code would look like this:
const myCallBack = (searchterm) => {
return this.searchFacilities;
}
As you can see, searchFacilities is neither invoked nor does it receive the searchterm param.
You could have run into the same problem with a NON-ARROW function by writing the following code (although the syntax of arrow functions does make the mistake more likely and insidious):
const myCallBack = function(searchterm) {
return this.searchFacilities;
}
Because you're getting a reference to the searchTerm but you're not doing anything with it. You could just do this.searchTerm$.subscribe(this.searchFacilities) and the term will be passed into the function.
You searchFacilities function is declared in global scope, and then is called inside of ngOnInit as a callback and its context is not anymore global scope, now this points to ngOnInit element Object. In order to work inside ngOnInit object you need to bind it and then searchFacilities be method of ngOnInit and in this way its going to work.

proper function calling etiquette?

I may be wording this title wrong but in javascript is it ok to call a nested function like so, if not why and what are some safer or more proper ways
function foo() {
return function poo() {
console.log("ew");
}
}
var fooPoo = foo()();
Yes, that's fine, and fairly normal, if you want poo to have access to information that's private within foo and you don't want the calling code to have access to that information. Or even just if foo is what knows how to create the poo function, even if private information isn't needed.
It's relatively rare to do it all in one expression, because usually when you return a function from another function, you want to keep the function around:
var p = foo();
var fp1 = p();
var fp2 = p();
...but only relatively unusual, not unusual.
Here's an example of using the private information held by the context of the original call to the function (allocator, here, is like your foo):
function allocator(seed) {
return function() {
return seed++;
};
}
var a = allocator(1);
console.log(a()); // 1
console.log(a()); // 2
console.log(a()); // 3
Note that the code calling a can't manipulate seed directly. It can only call a and use the value it returns.
Yes, it as a functional technique referred to as currying. it allows you to set parameters for the function in different places in your code
function foo(param1) {
return function poo(param2) {
console.log(param1, param2);
}
}
var fooPoo = foo('param1')('param2');
A common thing I do is use currying for passing in settings when running event listeners to allow greater reuse of functions
function setColor(color) {
return function (e) {
e.target.background = color
}
}
someElement.addEventLister('click', setColor('red'))
Here you can pass in your configuration when declaring your event listener but it won't be called until later when the event is fired and due to the closure you will have access to the color variable within the event listener callback. But now that I know the technique I use it quite a bit

overriding fullcalendar javascript functions which is in another script

I am newbie in js and I want to override/overwrite some fullcalendar functions from another script (my-fullcalendar.js) to make some changes in it for myself. for example function names are :
formatRange and oldMomentFormat.
formatRange is accessible from this.$.fullCalendar.formatRange but oldMomentFormat is not accessible via this kind of chain. But even when I do something like this in my-fullcalendar.js:
;(function () {
function MyformatRange(date1, date2, formatStr, separator, isRTL) {
console.log( "MyformatRange");
//other parts is exactly the same
// ...
}
this.$.fullCalendar.formatRange=MyformatRange;
console.log(this);
})();
nothing happens because no log is generated and even line by line tracing does not pass from here. but when observing "this" in console log MyformatRange replaced by original formatRange.
another problem is how can I override/overwrite oldMomentFormat function which is not in window hierarchy to access (or I can not find it) ??
OK, let's simplify the problem. In essence, you have this situation:
var makeFunObject = function () {
var doSomething = function (msg) {
console.log(msg);
};
var haveFun = function () {
doSomething( "fun!");
};
return {
doSomething : doSomething,
haveFun : haveFun
};
};
In other words you have a function that is creating a closure. Inside that closure are two "private" functions, one of which calls the other. But both functions seem to be "exposed" in the returned object.
You write some code:
var myFunObject = makeFunObject();
myFunObject.haveFun(); // fun!
Yep, seems to work just fine. Now let's replace the doSomething function in that returned object and call haveFun again:
myFunObject.doSomething = function (msg) {
console.log("My new function: " + msg);
};
myFunObject.haveFun(); // fun! <== wait what?
But wait! The new replacement function is not being called! That's right: the haveFun function was expressly written to call the internal function. It in fact knows nothing about the exposed function in the object at all.
That's because you cannot replace the internal, private function in this way (you cannot replace it at all, in fact, not without altering the original code).
Now draw back to the FullCalendar code: you are replacing the external function in the object, but the internal function is the one that is called by every other function inside FullCalendar.
I realize this is an old question, but I was butting my head against this same problem when I wanted to override the getEventTimeText function.
I was able to accomplish this, from inside my own JS file, like so:
$.fullCalendar.Grid.mixin({
getEventTimeText: function (range, formatStr, displayEnd) {
//custom version of this function
}
});
So, in terms of the function you were trying to override, you should be able to do it with:
$.fullCalendar.View.mixin({
formatRange: function (range, formatStr, separator) {
//custom formatRange function
}
});
Note: Make sure this runs before where you actually create the calendar. Also note that you need to make sure to override the function in the right place. For example, getEventTimeText was in $.fullCalendar.Grid, while formatRange is in $.fullCalendar.View.
Hopefully this helps other people who end up on this question.

Passing parameters to callback function without changing method (Siesta Testing namespace)

Does anyone know how to pass parameters to a callback function that you cannot alter?
So here is the code I'm trying to implement (It is a siesta testing method):
Base.js:
waitForComponentQueryVisible: function (parentNext, parameters) {
var th = this,
query = parameters.query,
scope = th,
callback = callFunct,
timeout = 10000;
//The function inside here (returnToParentTester(parentNext, parameters)) is from Base.js
callFunct = function () {
scope.returnToParentTester(parentNext);
}
this.test.waitForComponentQueryVisible(query, callback, scope, timeout);
},
The problem here is of two parts:
1. I cant get the scope just right so I can use the returnToParentTester method that is found in Base.js
2. I want to pass in parentNext into the method but cannot do that when defining it as a callback
this is the method I need to run as the callback:
Base.js:
returnToParentTester: function (parentNext, parameters) {
debugger;
if (parentNext) {
parentNext.call(undefined, parameters);
} else {
this.test.fail('--Developer Error-- undefined parentNext ' +
'variable. All the chains are going to fail');
}
},
I can't get the scope just right so I can use the returnToParentTester method that is found in Base.js
Use the call method to change the scope:
Base.returnToParentTester.call(myScope)
I want to pass in parentNext into the method but cannot do that when defining it as a callback
Use an anonymous function as a callback and pass parameters within its scope:
$("body").click(function(e){foo(e.target,bar,baz)})
then let it do the work:
function foo(myScope, next1, param1)
{
Base.returnToParentTester.call(myScope, next1, param1)
}
References
Fast JavaScript max/min
Mixins and Constructor Functions
Function.prototype.apply revisited
applyFunctionArguments - argument injection technique in JavaScript
Functional JavaScript, Part 3: .apply(), .call(), and the arguments object

Categories