JavaScript function: what does this do? - javascript

I have been looking at this code for sometime now, trying to understand what it does but I can't really get my head around it. I need help with understanding what this function actually does
function element(array, gen) {
if(gen === undefined) {
gen = fromTo(
0,
array.length
);
}
return function() {
var index = gen();
if(index !== undefined) {
return array[index];
}
};
}
function concat(...gens) {
var next = element(gens),
gen = next();
return function recur() {
var value = gen();
if(value === undefined) {
gen = next();
if(gen !== undefined) {
return recur();
}
}
return value;
};
}

element is not a javascript built-in which means it must be defined elsewhere. Without knowing its function, it is impossible to say exactly what is happening, but here is what I can tell you.
concat takes n arguments of the same type. Without knowing what element does I can't tell you what type that is, but it can take as many as you need to give it. That is what the spread operator ... is telling you.
It returns a function that takes 0 arguments. When called, it continues to call itself checking if the return value of gen() is defined, if it is not, it changes gen to be the return value of next() and calls gen() again. It repeats this process until the return value of gen() is defined, and then returns that value.
Using it would look something like this.
var recur = concat(a,b,c,d,e); // can take any number of arguments of the same type
var someValue = recur(); // calls itself until it has a value to return
console.log(someValue); // use the value

Related

Arguments Optional FreeCodeCamp Challenge

in need of help with a codecamp challenge:
Arguments Optional - The challenge
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/arguments-optional
My Question
I know this can be done with the arguments object (see figure 1), where I can call the function again when the second value is undefined so I've gone for a different approach; However, my code of using currying works but becomes an issue with 'addTogether(5)(7);'
Issue ->
I get the returned value of 12 but doesn't get approved in the code challenge.
I did originally return the value inside the sum function but the challenge required the sum value to be returned in addTogether function, which I did so now it resulting in the following
addTogether(2,3); // now working
addTogether(5)(7); // NOT working
addTogether(23, 30); // now working
Is there something I'm doing wrong that's resulting in the test case failing even though the correct value is returned?
let val = 0;
function sum(a, b) {
val = a + b;
}
function sumTwoAnd(sumFunc) {
return function addTogether(...params) {
let numsArr = [...params];
const res = numsArr.every(el => typeof el === 'number');
if (res === false) return;
if (numsArr.length >= sumFunc.length) {
sumFunc(...numsArr);
} else {
return function(...args2) {
let newArr = numsArr.concat(args2);
addTogether(...newArr);
}
}
console.log(val);
return val;
}
}
let addTogether = sumTwoAnd(sum);
addTogether(2,3);
addTogether(5)(7);
addTogether(23, 30);
Figure 1
Shows how I can get 'test(5)(7)' the second parameter from the function
function test() {
const [f, s] = arguments;
console.log(f, s)
if (s === undefined) {
return s => test(f, s)
}
}
test(23, 30);
test(5)(7);
You declared addTogether using let, so the declaration won't be hoisted above the point where it was defined. This is making your recursive call in the else statement fail, since addTogether() doesn't exist that far up.
You might want to extract the function you're returning in sumTwoAnd() as a separate function definition, so it can freely call itself, similar to your Figure 1 example.
Or you can call sumTwoAnd() instead to regain the function, then pass newArr to said function.
Instead of calling the function I have now returned it...
return addTogether(...newArr);
This now works :)

JS how to do something only once

For example:
// run this:
alert('Loading...');
// dont run this again:
alert('Loading...');
I don't want to ever repeat that.
How can I do this with convenience (preferably without using booleans)?
The standard way is to use a boolean flag.
But, if you have an aversion to booleans, you can do it by overwriting the function, thus ensuring it literally can never be called again.
function loadButOnlyOnce() {
console.log('This will only happen once!');
loadButOnlyOnce = function() {};
}
loadButOnlyOnce();
loadButOnlyOnce();
Your IDE will probably spew out warnings along the lines of "What are you doing, this is overwriting the function!". But it's your code, and you can do it if you want.
So, now you want a generic solution you can use with different functions? You can do this like so:
function allowOnlyOneCall(f) {
return function() {
f.apply(this, arguments);
f = function() {};
}
}
function myMethod(p1) {
console.log('myMethod is being invoked. p1 = ' + p1);
}
myMethod = allowOnlyOneCall(myMethod);
myMethod(5);
myMethod(5);
Here is one clean implementation you could use so you can avoid the usage of booleans for every single task you don't want to repeat:
var cache = [];
function do_once(task, fn) {
if(cache.indexOf(task) == -1) { // shorthand: !~cache.indexOf(task)
cache.push(task);
return fn();
}
}
Usage:
var alertLoading = alert.bind(null, "Loading...");
do_once("alert_loading", alertLoading); // will run
// later on...
do_once("alert_loading", alertLoading); // will not run again
This works as long as you give each task you don’t want to repeat a different name. Regardless of the function provided as the second argument to do_once, it will not run as long as do_once has already been called using the same task name.
First create a variable to store whether the function has already run or not (such as hasRun). Then simply store your functionality inside an if condition which checks that this variable is false. You would need to update this variable after running the logic for the first time.
This can be seen in the following:
hasRun = false;
document.getElementsByTagName('button')[0].addEventListener('click', function() {
if (!hasRun) {
console.log('Loading...'); // Gets run once
hasRun = true; // Set the flag to true so the conditional doesn't get entered again
} else {
console.log('The function already ran!'); // Runs every subsequent time
}
})
<button>Click me</button>
If you want a factory function that memoizes the result of calling a function with a single primitive value as a parameter, you should use a Map:
const once = (() => fn => {
const cache = new Map()
return value => {
if (!cache.has(value)) {
cache.set(value, fn(value))
}
return cache.get(value)
}
})()
function verboseSquare (value) {
console.log('expensive calculation')
return value * value
}
const squareOnce = once(verboseSquare)
console.log(squareOnce(4))
console.log(squareOnce(4)) // skipped work
console.log(squareOnce(5))
console.log(squareOnce(5)) // skipped work

In JavaScript, how to execute next function from an array of functions

I have an array of functions, as in:
funcArray = [func1, func2, func3];
When in a given function, I want to execute the next function in the array. How do I do this? Here is my basic skeleton:
function func1() {
// I get current function caller
var currentFunc = func1.caller;
// I want to execute the next function. Happens to be func2 in the example.
}
I cannot use indexOf function, as one would for an array of strings or numbers.
NOTE: This question appears to be similar to this and the one it refers to. However, it is a different question.
I want to alter the sequence of processing by merely modifying the array. That's the goal. A possibly more efficient approach would be appreciated.
Clarification: Based upon some of the comments:
funcArray is global.
The goal is to implement middleware for a Node.js HTTP module in as simple and efficient a manner as possible without using any third-party modules.
Unless func1 closes over funcArray, you cannot have it reach out and find func2 and execute it, nor should you. Even if func1 does close over funcArray, it would be poor separation of concerns for func1 to reach out and find itself in funcArray and then execute func2.
Instead, have other code that's in charge of running the functions.
If they're synchronous
If the functions complete their work synchronously, then it's simply:
funcArray.forEach(fn => fn());
or
for (const fn of funcArray) {
fn();
}
or if the result of one function should be passed to the next, you can use reduce:
const finalResult = funcArray.reduce((previousResult, fn) => fn(previousResult), undefined);
...where undefined is the value to pass to func1.
If they're asynchronous
If they don't do their work synchronously, you'll need to provide them a way to notify their caller that they've completed their work. Promises are a good, standard way to do that, but you could use simple callbacks instead.
If you make them return promises, for instance, you can use the old promise reduce trick:
funcArray.reduce((p, fn) => {
return p.then(() => {
fn();
});
}, Promise.resolve());
or if the result of one function should be passed to the next:
funcArray.reduce((p, fn) => {
return p.then(fn);
}, Promise.resolve());
You can provide an argument to Promise.resolve to set the value to pass to func1 (without one, it'll receive undefined).
You can bind to the function the index where it is in the array so you can use this index to get and call the next function:
var funcArray = [func1, func2];
var boundFuncArray = funcArray.map((f, i) => f.bind(null, i));
boundFuncArray[0]();
function func1(nextFunctionIndex) {
console.log('func1 called');
// Execute next function:
var nextFunc = boundFuncArray[nextFunctionIndex + 1];
nextFunc && nextFunc();
}
function func2(nextFunctionIndex) {
console.log('func2 called');
// Execute next function:
var nextFunc = boundFuncArray[nextFunctionIndex + 1];
nextFunc && nextFunc();
}
As T.J Crowder stated in the comment below, you can also bind the next function to the current one:
var funcArray = [func1, func2];
var boundFuncArray= funcArray.map((f, i, arr) => f.bind(null, arr[i + 1]));
boundFuncArray[0]();
function func1(nextFunc) {
console.log('func1 called');
// Execute next function:
nextFunc && nextFunc();
}
function func2(nextFunc ) {
console.log('func2 called');
// Execute next function:
nextFunc && nextFunc();
}
You can get the current function's name with arguments.callee.name, loop through the array of functions, and call the next function:
funcArray = [func1, func2, func3];
// Only func1() and func2() will be documented since the others have repeating code
function func1() {
// show the current function name
console.log(arguments.callee.name);
// loop the array of functions
for(var i = 0; i < funcArray.length; ++i)
{
// when the current array item is our current function name and
// another function exists after this then call it and break
if(funcArray[i] === arguments.callee && funcArray[i+1])
{
funcArray[i+1]();
break;
}
}
}
function func2() {
console.log(arguments.callee.name);
// some logic which switches our next function to be func4()
funcArray[2] = func4;
for(var i = 0; i < funcArray.length; ++i)
{
if(funcArray[i] === arguments.callee && funcArray[i+1])
{
funcArray[i+1]();
break;
}
}
}
function func3() {
console.log(arguments.callee.name);
for(var i = 0; i < funcArray.length; ++i)
{
if(funcArray[i] === arguments.callee && funcArray[i+1])
{
funcArray[i+1]();
break;
}
}
}
function func4() {
console.log(arguments.callee.name);
for(var i = 0; i < funcArray.length; ++i)
{
if(funcArray[i] === arguments.callee && funcArray[i+1])
{
funcArray[i+1]();
break;
}
}
}
// call the first function
funcArray[0]();
Output:
func1
func2
func4
I have solved it this way:
// Adding next options to array
function addNext(array) {
array.last = 1
Object.defineProperty(array, 'next', {get:
function() {
if(this.last < this.length) {
this.last++
return this[this.last-1]
} else {
this.last = 1
return () => {}
}
}
});
}
// The functions for array (has to be function and not arrow function)
function first(param) {
console.log('first',param)
return this.next(param)
}
function second(param) {
console.log('second',param)
return this.next(param)
}
function third(param) {
console.log('third',param)
return this.next(param)
}
// The array
let fns = [first,second,third]
// Adding next option to array
addNext(fns)
// Run first function from array
fns[0]('test')
I dont know if your functions require certain parameters but this is the first thing that came to my mind.
var functArray = [
function() {
console.log("function1 executed");
},
function() {
console.log("function2 executed");
},
function() {
console.log("function3 executed");
},
function() {
console.log("function4 executed");
}];
functArray.forEach(function(x){
x();
});
The accepted answer and other comments did help me, but the way I implemented it is as follows:
//The functions are defined as variables.
//They do not get hoisted, so must be defined first.
func1 = function (arg1, arg2) {
//Code to do whatever...
...
//Execute the next function.
//The name of the function is returned by executing nextFunc()
global[nextFunc()](arg1, arg2, arg3);
}
func2 = function (arg1) { //Note different type of args
...
}
//Note that this is an array of strings representing function names.
funcArray = ["func1", "func2", "func3",...]
//Start the execution...
func1(arg1, arg2);
function nextFunc() {
var currentFuncName = nextFunc.caller.name;
var index = funcArray.indexOf(currentFuncName);
if (index < funcArray.length)
return funcArray[index+1];
}
The sequence of functions to be executed is easily managed through the array funcArray. The number or type of arguments is not fixed for each function. Additionally, the functions control if they should stop the chain or continue with the next function.
It is very simple to understand requiring basic Javascript skills. No overheads of using Promises.
"global" gets replaced by "window" for browser. This is a Node.js implementation. The use of function names in the array will, however, break if you minify the JS code. As I am going to use it on the server, I do not expect to minify it.
You can do it in this way with promise.all if your functions to be executed in parallel.
let toBeExecutedList = [];
toBeExecutedList.push(() => this.addTwoNumber(2, 3));
toBeExecutedList.push(()=>this.square(2));
And Then wherever you want to use them, do it like this:
const resultArr = await Promise.all([
toBeExecutedList.map(func => func()),
]);

Synchronous way of handling asynchronous function, two level deep

I am looping over an array to update its values using returned value from called function which internally calls an asynchronous function.
I need to handle asynchronous function in synchronous way which is not being directly called. This is replication of scenario.
function condition(){
// Code of this function is not accessible to me.
return new Promise(function(resolve, reject){
setTimeout(function(){
if(parseInt(Math.random() * 100) % 2){
resolve(true);
}
else{
reject(false)
}
}, 1000)
});
}
async function delayIncrease(value){
var choice = await condition();
if(choice) { return ++value; }
else { return --value; }
}
// Start calling functions
dataArr = [1,2,3,4,5];
for(var i in dataArr){
dataArr[i] = delayIncrease(dataArr[i]);
}
If possible, I would like to have the solution in above structure mentioned.
I have achieved the desired result by adding other function and passing "index" + "new_value" as parameters. This function directly modifies original array and produces desired result. Working example.
function condition(){
// Code of this function is not accessible to me.
return new Promise(function(resolve, reject){
setTimeout(function(){
if(parseInt(Math.random() * 100) % 2){
resolve(true);
}
else{
reject(false)
}
}, 1000)
});
}
function delayIncrease(value, index){
condition().then(
function(){ updateData(++value, index) },
function(){ updateData(--value, index) }
)
}
function updateData(value, index){
dataArr[index] = value;
}
dataArr = [1,2,3,4,5];
for(var i in dataArr){
dataArr[i] = delayIncrease(dataArr[i], i);
}
Please provide solution for this requirement in best possible way. Possible solution in Angular 4 way is also appriciated. I thought of writing it in normal JavaScript form as Observables behave nearly same.
I followed this Medium page and http://exploringjs.com
Your condition function does not really fulfill the promise with either true or false, it does randomly fulfill or reject the promise. Instead of branching on a boolean, you will need to catch that "error":
async function delayIncrease(value) {
try {
await condition();
return ++value;
} catch(e) {
return --value;
}
}
You could do something like this:
var condition = async () =>
(parseInt(Math.random() * 100) % 2)
? true
: false
var delayIncrease = async (value) =>
(await condition())
? ++value
: --value
var dataArr = [1, 2, 3, 4, 5];
// Start calling functions
Promise.all(
dataArr.map(
delayIncrease
)
)
.then(
resolve => console.log("results:",resolve)
,reject => console.warn("rejected:",reject)
)
Once something is async you have to make the entire call stack prior to that function async. If a function calls an async function that that function returns an async value and so does the one calling it and calling it and calling it ...
More info on javascript async and why can be found here.
Since the example provided doesn't have any async api's in there you don't need to do it async:
var condition = () =>
(parseInt(Math.random() * 100) % 2)
? true
: false
var delayIncrease = (value) =>
(condition())
? ++value
: --value
var dataArr = [1, 2, 3, 4, 5];
// Start calling functions
dataArr.map(
delayIncrease
)
[update]
When you mutate an array of objects and cosole.log it you may not see the values as they actually were when you log it but you see the values as they are right now (this is a "bug" in console.log).
Consider the following:
var i = -1,arr=[];
while(++i<1){
arr[i]={};
arr[i]["name"+i]=i
}
var process = (index) =>
arr[index]["name"+index]++;
arr.forEach(
(item,index) =>
Promise.resolve(index)
.then(process)
);
console.log("obj at the moment you are looking at it:",arr)
console.log("obj at the moment it is logged:",JSON.stringify(arr))
When you expand obj at the moment you are looking at it you see that name0 property of the first element changed to 1.
However; look at obj at the moment it is logged: and see the actual value of the first element in the array. It has name0 of 0.
You may think that the that code runs asynchronous functions in a synchronous way by mutating the object(s) in an array, but you actually experience a "bug" in console.log

Create a function with an undetermined number of successive calls

As part of a programming challenge, we are tasked with creating a function with an undetermined number of successive calls. As an example, let's say the function returns simply the sum of the provided arguments, it should work as follows :
sum(4)() // 4
sum(4)(5)() // 9
sum(4)(5)(9)() // 18
sum(4)(5)(9)(1)() // 19
// etc...
The problem is simplified by the allowed empty function call at the end as an indication of end of calls.
I have worked on a solution that does the job but using global variables inside the function itself :
var sum = function (a) {
if (!sum.init) {
sum.total = 0;
sum.init = true;
}
if (!arguments.length) {
sum.init = false;
return sum.total;
}
sum.total += a;
return sum;
};
This solution works but uses state, global variables and function object trickery which is not ideal. My question here is whether there is a way to solve the problem in a purely recursive way.
As a side note, I do not believe the problem can be solved if that last empty call () is not provided, but if I'm wrong please let me know.
Update
This issue has been answered in CodeReview : https://codereview.stackexchange.com/a/153999/129579
A neet solution that does not rely on global scope and is purely functional.
You can make use of closures to acheive what you want like this:
function sum(value){
// the closure variable that will be accessible for all the _sum calls (initialised to 0 for every sum call).
var result = 0;
// the function that will be returned (sum will only get called once to initialize the result to 0. It's _sum which will be returned as much as possible)
function _sum(a){
// if we passed a parameter, then add it to result and return a new _sum
if(typeof a != "undefined"){
result += a;
return _sum;
}
// if we didn't return the result
else
return result;
}
// of course after initializing result we need to call _sum that handle the actual summing and return whatever it returns (if value is defined, it will return another `_sum` if not it will return the value of result which will be 0 at first) from now on sum will have nothing to do with the rest of the calls (()()()... )
return _sum(value);
}
console.log("sum() = " + sum());
console.log("sum(7)() = " + sum(7)());
console.log("sum(5)(6)(7)() = " + sum(5)(6)(7)());
// will return 0 because we call sum again
console.log("sum() = " + sum());
NOTE: That sum(1)(7)(3)()); will call, in this order:
sum with the parameter 1 which will initialize result to 0 and call
_sum with the same parameter 1 which will add it to result and return a new inctance of _sum which will be called so the following
_sum get called with the parameter 7, add it and return a new _sum so the new
_sum get called with the parameter 3, ... spawn another
_sum that will have no parameter, therefore if(typeof a != "undefined") will fail and this _sum will return result instead.
The actual sum is only called once at the begining to do the initialization. It's, as I said, _sum that get chained after that all the way to the end.
Basically you could use an outer function sum for the initial call and a closure over the starting value a and an inner function fn, which is repeatingly returned and only exited if arguments.length is equal to zero.
If a value b is supplied, the variable a gets updated and the inner function fn gets returned.
function sum(a) {
return function fn(b) {
if (!arguments.length) {
return a;
}
a += b;
return fn;
};
}
console.log(sum(1)());
console.log(sum(1)(2)());
console.log(sum(1)(2)(3)());
Edit for calling sum with no argument
function sum(a) {
return arguments.length ?
function fn(b) {
if (!arguments.length) {
return a;
}
a += b;
return fn;
} :
0;
}
console.log(sum());
console.log(sum(1)());
console.log(sum(1)(2)());
console.log(sum(1)(2)(3)());

Categories

Resources