158

Is there a way in Javascript to write something like this easily:

[1,2,3].times do {
  something();
}

Any library that might support some similar syntax maybe?

Update: to clarify - I would like something() to be called 1,2 and 3 times respectively for each array element iteration

BreakPhreak
  • 10,940
  • 26
  • 72
  • 108
  • 4
    I would say there is no feature like this in JS, and it's a top 5 missing feature. It is very useful for testing software, more than anything. – Alexander Mills Jan 18 '17 at 20:01

23 Answers23

154

Just use a for loop:

const times = 10;

for(let i = 0; i < times; i++){
    doSomething();
}
Aiden Cullo
  • 312
  • 3
  • 15
ahren
  • 16,803
  • 5
  • 50
  • 70
  • 8
    thank you! I would like to benefit from a declarative syntax (just like Jasmine etc) – BreakPhreak Jun 12 '12 at 09:28
  • 3
    right, but a functional for-loop declarative syntax would also be much better – Alexander Mills Jan 18 '17 at 19:59
  • 3
    Yes please, I'm sick and tired of being forced declarative shit all over for no reason. It's a great tool to use when you need it, but a tool not a holy mandate. – Mihai Nov 11 '21 at 10:50
  • 3
    Or use a `while(times--)` if you want it in less keystrokes! – Positivity Jan 20 '22 at 17:07
  • 1
    Just profiled this, on both Chrome and Firefox currently, this imperative syntax is faster than any of the the declarative syntax versions described in this question. tl;dr: Yes, use a `for` loop. – Charles Lohr Aug 25 '22 at 07:05
129

Possible ES6 alternative.

Array.from(Array(3)).forEach((x, i) => {
  something();
});

And, if you want it "to be called 1,2 and 3 times respectively".

Array.from(Array(3)).forEach((x, i) => {
  Array.from(Array(i+1)).forEach((x, i2) => {
    console.log(`Something ${ i } ${ i2 }`)
  });
});

Update:

Taken from filling-arrays-with-undefined

This seems to be a more optimised way of creating the initial array, I've also updated this to use the second parameter map function suggested by @felix-eve.

Array.from({ length: 3 }, (x, i) => {
  something();
});
nverba
  • 3,803
  • 2
  • 18
  • 21
  • 3
    I should caveat this by saying this is ok if you're just quickly scripting something up, but the performance is horrible, so don't use it for intensive recursion or in production at all probably. – nverba Jan 21 '17 at 09:44
  • If you're going for ES6, you can use map() instead of forEach() – Andy Ford Feb 22 '17 at 12:11
  • `map` and `forEach` are both ES5 – Phil Mander Mar 03 '17 at 10:55
  • Indeed, it's `Array.from` that falls under ES6, and in this instance, the arrow functions are really unnecessary. They're just used for terseness. – nverba Mar 06 '17 at 10:16
  • 3
    If terseness is the goal (and actually, even if it isn't), pass the function instead of calling it: `Array.from(Array(3)).forEach(something)` – kvsm Jul 09 '18 at 00:39
  • 1
    Works with react expression rendering as well. – Josh Sharkey Dec 08 '18 at 21:38
  • 8
    [`Array.from()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) has an optional second parameter `mapFn`, which allows you to execute a map function on each element of the array, so there is no need to use forEach. You can just do: `Array.from({length: 3}, () => somthing() )` – Felix Eve Nov 22 '19 at 09:42
  • 1
    `Array.from({length: 3}, something)` – Toxiro Jun 29 '23 at 22:17
75

The easiest way is by destructuring the Array,

which automatically sets undefined for each item, if the item's value was not set:

[...Array(5)].map((item, i) => console.log(item, i))

The keys Array method can also be used to generate an Array of indices values:

[...Array(3).keys()] // [0, 1, 2]

Alternatively, create an Array and fill all items with undefined before using map:

Read detailed reason why map is skipping never-defined array items

⚠️ Array.fill has no IE support

Array(5).fill().map((item, i) => console.log(item, i))

If you want to make the above more "declarative", my currently opinion-based solution would be:

const iterate = times => callback => [...Array(times)].map((n,i) => callback(i))

iterate(3)(console.log)

Using old-school (reverse) loop:

// run 5 times:
for( let i=5; i--; )
   console.log(i) 

Or as a declarative "while":

const run = (cb, ...args) => count => { while(count--) cb(...args) }

// executes the callback with whatever arguments, 3 times
run(console.log, 1,2,3)(3)
vsync
  • 118,978
  • 58
  • 307
  • 400
  • 4
    For piece of mind I ran a uuid function **50k times** to make sure it never duplicated a uuid. So I profiled the top loop vs the bottom just for kicks, just running in the middle of a normal page load using chrome dev tools **if im not being dumb I think its ~1.2billion compares using Array.indexOf()** plus generating 50k uuids. **newschool = 1st-5561.2ms 2nd-5426.8ms | oldschool = 1st-4966.3ms / 2nd-4929.0ms** Moral of the story if u are not in the billion+ range u would never notice a difference running these 200, 1k, even 10k times to do something. Figured someone might be curious like me. – rifi2k Feb 15 '19 at 03:22
  • That is correct and has been known for many years. The different approaches were not presented for speed benefits but for older browsers' support. – vsync Feb 15 '19 at 09:41
  • 3
    Odviously everyone that reads this thread, knows you didn't present the examples to compare their speed. I just happened to use them to run a little test and figured I would share some info that someone down the road might find interesting. I'm not really correct because I wasn't really answering a question just displaying information and giving a reminder to not sweat the speed of a loop when your only doing a few things that will end in a couple ms anyways. It's not really known either because the same test a year ago in ie may find one 50% slower because browsers change all the time. – rifi2k Feb 15 '19 at 10:33
  • 3
    or `for(var i=10; i--; console.log(i));` – Alex Szücs Feb 03 '22 at 16:30
51

This answer is based on Array.forEach, without any library, just native vanilla.

To basically call something() 3 times, use:

[1,2,3].forEach(function(i) {
  something();
});

considering the following function:

function something(){ console.log('something') }

The output will be:

something
something
something

To complete this questions, here's a way to do call something() 1, 2 and 3 times respectively:

It's 2017, you may use ES6:

[1,2,3].forEach(i => Array(i).fill(i).forEach(_ => {
  something()
}))

or in good old ES5:

[1,2,3].forEach(function(i) {
  Array(i).fill(i).forEach(function() {
    something()
  })
}))

In both cases, the output will be

The output will be:

something

something
something

something
something
something

(once, then twice, then 3 times)

robd
  • 9,646
  • 5
  • 40
  • 59
vinyll
  • 11,017
  • 2
  • 48
  • 37
  • 23
    This is incorrect because it doesn't satisfy this part of the question: 'I would like something() to be called 1,2 and 3 times'. Using this code `something` is only called 3 times, it should be called 6 times. – Ian Newson Aug 31 '16 at 11:45
  • Then I guess it's been selected as _best answer_ as it may be a good cleaner start. – vinyll Jan 20 '17 at 23:33
  • 4
    You could also use `[...Array(i)]` or `Array(i).fill()`, depending on your needs for the actual indexes. – Guido Bouman Feb 15 '18 at 11:06
  • 1
    If you're not interested in any arguments passed, use `.forEach(something)` – kvsm Jul 09 '18 at 00:44
25

With lodash:

_.each([1, 2, 3], (item) => {
   doSomeThing(item);
});

//Or:
_.each([1, 2, 3], doSomeThing);

Or if you want to do something N times:

const N = 10;
_.times(N, () => {
   doSomeThing();
});

//Or shorter:
_.times(N, doSomeThing);
Tho
  • 23,158
  • 6
  • 60
  • 47
18

Since you mention Underscore:

Assuming f is the function you want to call:

_.each([1,2,3], function (n) { _.times(n, f) });

will do the trick. For example, with f = function (x) { console.log(x); }, you will get on your console: 0 0 1 0 1 2

ggozad
  • 13,105
  • 3
  • 40
  • 49
16

You can also do the same thing with destructuring as follows

[...Array(3)].forEach( _ => console.log('do something'));

or if you need index

[...Array(3)].forEach(( _, index) => console.log('do something'));
Ozay Duman
  • 447
  • 3
  • 6
14

How about a simple while.

let times = 5;

while (times--) {

    console.log(times+1)

}

References on how this works: Falsy and Decrement (--)


Edit: If there's a possibility for times to be manipulated elsewhere, it's safer to use times-- > 0 instead of times-- to prevent an infinite loop if the times drops below 0

Positivity
  • 5,406
  • 6
  • 41
  • 61
9

If you can't use Underscorejs, you can implement it yourself. By attaching new methods to the Number and String prototypes, you could do it like this (using ES6 arrow functions):

// With String
"5".times( (i) => console.log("number "+i) );

// With number variable
var five = 5;
five.times( (i) => console.log("number "+i) );

// With number literal (parentheses required)
(5).times( (i) => console.log("number "+i) );

You simply have to create a function expression (of whatever name) and assign it to whatever property name (on the prototypes) you would like to access it as:

var timesFunction = function(callback) {
  if (typeof callback !== "function" ) {
    throw new TypeError("Callback is not a function");
  } else if( isNaN(parseInt(Number(this.valueOf()))) ) {
    throw new TypeError("Object is not a valid number");
  }
  for (var i = 0; i < Number(this.valueOf()); i++) {
    callback(i);
  }
};

String.prototype.times = timesFunction;
Number.prototype.times = timesFunction;
Andreas Bergström
  • 13,891
  • 5
  • 59
  • 53
2

Array.from (ES6)

function doSomthing() {
    ...
}

Use it like so:

Array.from(Array(length).keys()).forEach(doSomthing);

Or

Array.from({ length }, (v, i) => i).forEach(doSomthing);

Or

// array start counting from 1
Array.from({ length }, (v, i) => ++i).forEach(doSomthing);
Community
  • 1
  • 1
Lior Elrom
  • 19,660
  • 16
  • 80
  • 92
1

Just use a nested loop (maybe enclosed in a function)

function times( fct, times ) {
  for( var i=0; i<times.length; ++i ) {
    for( var j=0; j<times[i]; ++j ) {
      fct();
    }
  }
}

Then just call it like this:

times( doSomething, [1,2,3] );
Sirko
  • 72,589
  • 19
  • 149
  • 183
1
times = function () {
    var length = arguments.length;
    for (var i = 0; i < length ; i++) {
        for (var j = 0; j < arguments[i]; j++) {
            dosomthing();
        }
    }
}

You can call it like this:

times(3,4);
times(1,2,3,4);
times(1,3,5,7,9);
XU3352
  • 147
  • 1
  • 5
  • +1 - This utilizes the native JavaScript ability to call functions with variable amounts of parameters. No extra library needed. Nice solution – RustyTheBoyRobot Jun 12 '12 at 17:26
1
const loop (fn, times) => {
  if (!times) { return }
  fn()
  loop(fn, times - 1)
}

loop(something, 3)
Goro
  • 990
  • 8
  • 7
1

There is a fantastic library called Ramda, which is similar to Underscore and Lodash, but is more powerful.

const R = require('ramda');

R.call(R.times(() => {
    console.log('do something')
}), 5);

Ramda contains plenty of useful functions. See Ramda documentation

Jan Bodnar
  • 10,969
  • 6
  • 68
  • 77
0

you can use

Array.forEach

example:

function logArrayElements(element, index, array) {  
    console.log("a[" + index + "] = " + element);  
}  
[2, 5, 9].forEach(logArrayElements)

or with jQuery

$.each([52, 97], function(index, value) { 
  alert(index + ': ' + value); 
});

http://api.jquery.com/jQuery.each/

Machu
  • 69
  • 5
  • It looks like `forEach` is only supported in IE from version 9: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach – Bruno Jun 12 '12 at 09:36
0
// calls doSomething 42 times
Array( 42 ).join( "x" ).split( "" ).forEach( doSomething );

and

// creates 42 somethings
var somethings = Array( 42 ).join( "x" ).split( "" ).map( () => buildSomething(); );

or ( via https://stackoverflow.com/a/20066663/275501 )

Array.apply(null, {length: 42}).forEach( doSomething );
Community
  • 1
  • 1
goofballLogic
  • 37,883
  • 8
  • 44
  • 62
0

These answers are all good and well and IMO @Andreas is the best, but many times in JS we have to do things asynchronously, in that case, async has you covered:

http://caolan.github.io/async/docs.html#times

const async = require('async');

async.times(5, function(n, next) {
    createUser(n, function(err, user) {
        next(err, user);
    });
}, function(err, users) {
    // we should now have 5 users
});

These 'times' features arent very useful for most application code, but should be useful for testing.

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
0

Assuming we can use some ES6 syntax like the spread operator, we'll want to do something as many times as the sum of all numbers in the collection.

In this case if times is equal to [1,2,3], the total number of times will be 6, i.e. 1+2+3.

/**
 * @param {number[]} times
 * @param {cb} function
 */
function doTimes(times, cb) {
  // Get the sum of all the times
  const totalTimes = times.reduce((acc, time) => acc + time);
  // Call the callback as many times as the sum
  [...Array(totalTimes)].map(cb);
}

doTimes([1,2,3], () => console.log('something'));
// => Prints 'something' 6 times

This post should be helpful if the logic behind constructing and spreading an array isn't apparent.

IliasT
  • 3,973
  • 1
  • 24
  • 26
-1
var times = [1,2,3];

for(var i = 0; i < times.length;  i++) {
  for(var j = 0; j < times[i];j++) {
     // do something
  }
}

Using jQuery .each()

$([1,2,3]).each(function(i, val) {
  for(var j = 0; j < val;j++) {
     // do something
  }
});

OR

var x = [1,2,3];

$(x).each(function(i, val) {
  for(var j = 0; j < val;j++) {
     // do something
  }
});

EDIT

You can do like below with pure JS:

var times = [1,2,3];
times.forEach(function(i) {
   // do something
});
thecodeparadox
  • 86,271
  • 21
  • 138
  • 164
-1

Given a function something:

function something() { console.log("did something") }

And a new method times added to the Array prototype:

Array.prototype.times = function(f){
  for(v of this) 
    for(var _ of Array(v))
      f();
}

This code:

[1,2,3].times(something)

Outputs this:

did something
did something
did something
did something
did something
did something

Which I think answers your updated question (5 years later) but I wonder how useful it is to have this work on an array? Wouldn't the effect be the same as calling [6].times(something), which in turn could be written as:

for(_ of Array(6)) something();

(although the use of _ as a junk variable will probably clobber lodash or underscore if you're using it)

pix
  • 5,052
  • 2
  • 23
  • 25
-1

Using Array.from and .forEach.

let length = 5;
Array.from({length}).forEach((v, i) => {
  console.log(`#${i}`);
});
SeregPie
  • 1,223
  • 1
  • 18
  • 20
-1

TypeScript Implementation:

For those of you who are interested in how to implement String.times and Number.times in a way that is type safe and works with the thisArg, here ya go:

declare global {
    interface Number {
        times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
    }
    interface String {
        times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
    }
}

Number.prototype.times = function (callbackFn, thisArg) {
    const num = this.valueOf()
    if (typeof callbackFn !== "function" ) {
        throw new TypeError("callbackFn is not a function")
    }
    if (num < 0) {
        throw new RangeError('Must not be negative')
    }
    if (!isFinite(num)) {
        throw new RangeError('Must be Finite')
    }
    if (isNaN(num)) {
        throw new RangeError('Must not be NaN')
    }

    [...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
    // Other elegant solutions
    // new Array<null>(num).fill(null).forEach(() => {})
    // Array.from({length: num}).forEach(() => {})
}

String.prototype.times = function (callbackFn, thisArg) {
    let num = parseInt(this.valueOf())
    if (typeof callbackFn !== "function" ) {
        throw new TypeError("callbackFn is not a function")
    }
    if (num < 0) {
        throw new RangeError('Must not be negative')
    }
    if (!isFinite(num)) {
        throw new RangeError('Must be Finite')
    }
    // num is NaN if `this` is an empty string 
    if (isNaN(num)) {
        num = 0
    }

    [...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
    // Other elegant solutions
    // new Array<null>(num).fill(null).forEach(() => {})
    // Array.from({length: num}).forEach(() => {})
}

A link to the TypeScript Playground with some examples can be found here

This post implements solutions posted by: Andreas Bergström, vinyll, Ozay Duman, & SeregPie

Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
Noah Anderson
  • 799
  • 1
  • 7
  • 6
-1

Just thought I'd add, there is a nifty JS method called .repeat(n) which will repeat a string 'n' number of times. So if you're looking for something to repeat a string 'n' number of times...

function repeatString (number, string) {
  return string.repeat(number);
}

So if you did...

repeatString(3, 'Hey there! ');

You'd get: 'Hey there! Hey there! Hey there! '