forestkelley
forestkelley

Reputation: 341

How to invoke every array item when each array item is a function call

I have an array filled with function calls (i.e., func(param);) like this:

var array = [
  func(param),
  func(param),
  func(param)
];

At some later point, I want to invoke all of those function calls at once. How can I do that?

I know that you can run a function on each item in an array with a for loop or forEach like this:

for (var i = 0; i < 10; i++) {
  // do stuff
}

Or

arrayName.forEach(function(e) {
  // do stuff
});

But I'm not sure how to code this so that it will do the invoking?

I have tried what follows, but I get the error "arrayName[i] is not a function."

for (i = 0; i < arrayName.length; i++) {
  arrayName[i]();
}

EDIT: THREE SOLUTIONS

1: BEST, uses while loop

Here is the basic code:

var soundsWaitingForNextBar = [];

while (soundsWaitingForNextBar.length > 0) {
  soundsWaitingForNextBar[0](); // call first item in array
  soundsWaitingForNextBar.shift(); // remove first item in array
}

Here is a more in depth version where items are pushed to the array every second but the array is only emptied every ten seconds:

var soundsWaitingForNextBar = [];

function foo() {
  console.log('')
} // just making sure foo is a function

// pusing some functions into the array
soundsWaitingForNextBar.push(() => foo());
soundsWaitingForNextBar.push(() => foo());

setInterval(function() { // pushing items to array periodically to make sure the while loop is only emptying when it is called by setInterval and not every time an item is added to the array
  soundsWaitingForNextBar.push(() => foo());
}, 2000);


setInterval(function() {
  // this while loop does the magic: it calls and removes each item in the array
  while (soundsWaitingForNextBar.length > 0) {
    soundsWaitingForNextBar[0](); // call first item in array
    soundsWaitingForNextBar.shift(); // remove first item in array
  }
}, 10000);

setInterval(function() { // just checking to see how/when items are added to the array and emptied
  console.log('array.length: ' + soundsWaitingForNextBar.length);
}, 1000);

2: Uses array[0](); to call each array item/function.

const func = console.log;
const param = 'foo';

const array = [
  () => func(param),
  () => func(param),
  () => func(param)
];

console.log(array.length); // just noting the original array length

arrayLength = array.length;
for (let i = 0; i < arrayLength; i++) {
  array[0]();
  array.shift();
}

console.log(array.length); // just making sure the array is empty

3: Uses array.forEach(fn => fn()); to call each array item/function.

const func = console.log;
const param = 'foo';

const array = [
  () => func(param),
  () => func(param),
  () => func(param)
];

console.log(array.length); // just noting the original array length

array.forEach(fn => fn()); // calls each array item/function

arrayLength = array.length;
for (let i = 0; i < arrayLength; i++) {
  array.shift();
}

console.log(array.length); // just making sure the array is empty

Note: in the for loop that I originally used to remove items from the array with .splice, I used array.length. For example: for (let i = 0; i < array.length; i++). This didn't work (I'm not sure why) so I decided to determine the array length before the for loop using arrayLength = array.length;. Now the program works as intended.

Upvotes: 0

Views: 948

Answers (4)

Akrion
Akrion

Reputation: 18525

Your array is filled with results of function calls and not by functions the way you have it setup now. What you want to it store a function (anonymous or not) and execute it in your for loop.

You could also consider creating a function which to execute each of your functions and return an array with the results. For example you could Array.map through your array and since map returns an array as well you can have for each of your functions the actual result. Lets call the function invokeMap (similar to the same exact function which lodash has):

let add2 = x => x + 2

var fnArray = [  // array of anonymous functions
  (x) => x,  
  (x) => add2(x),
  (x) => add2(x) + add2(x)
];

let invokeMap = (arr, ...parrams) => arr.map((fn => fn(...parrams)))
 
let result = invokeMap(fnArray, 1) // pass one as a parameter to all functions

console.log(result)

Upvotes: 0

Hien Nguyen
Hien Nguyen

Reputation: 18973

You only need pass function name in array

var arrayName = [
  func,
  func,
  func
];

function func(a){
return a*2;
};
var arrayName = [
  func,
  func,
  func
];

for (i = 0; i < arrayName.length; i++) {
  console.log(arrayName[i](2));
}

Upvotes: 1

Jack Bashford
Jack Bashford

Reputation: 44135

Because currently you're storing the return value of func(param). Make each item a function reference to be able to call it later:

var array = [
  () => func(param),
  () => func(param),
  () => func(param)
];

Demo:

function func(p) {
  console.log(p);
}

let param = "Parameter";

var array = [
  () => func(param),
  () => func(param),
  () => func(param)
];

array.forEach(e => e());

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 371233

With

var array = [
  func(param),
  func(param),
  func(param)
];

you are already invoking those functions immediately, when the array is declared. It sounds like you want to defer their execution - you want them to be callable at some point in the future, not right now. instead, create an array of functions that, when called, call the function with the desired parameters, eg:

var array = [
  () => func(param),
  () => func(param),
  () => func(param)
];

Then, your for loop (or forEach) will work:

for (let i = 0; i < array.length; i++) {
  array[i]();
}

Demo:

const func = console.log;
const param = 'foo';

const array = [
  () => func(param),
  () => func(param),
  () => func(param)
];
array.forEach(fn => fn());

You can also use .bind instead of a higher-order function:

const func = console.log;
const param = 'foo';

const array = [
  func.bind(undefined, param),
  func.bind(undefined, param),
  func.bind(undefined, param)
];
array.forEach(fn => fn());

Upvotes: 1

Related Questions