repeat()

ES6+

Returns a new string consisting of the original repeated a given number of times, with the count coerced to an integer. A count of zero yields an empty string, and a negative or infinite count throws a RangeError. Added in ES2015, it replaced a family of loop-and-append and array-join tricks.

Syntax

string.repeat(count)

Parameters

count number

Number of times to repeat the string

Return Value

string

A new string containing the specified number of copies

Examples

JavaScript
const str = 'abc';
console.log(str.repeat(3));
console.log('='.repeat(10));
Output:
// 'abcabcabc' '=========='

📌 When to Use

Use repeat() to manufacture repetition on purpose: horizontal rules and separators for console output, indentation proportional to nesting depth, ASCII progress bars and charts, filler or placeholder text, and simple padding when the more specific padStart() and padEnd() do not fit the shape of the problem. The idiom indentUnit.repeat(depth) is the cleanest way to express tree-structured indentation, and '='.repeat(width) reads far better than the pre-ES2015 hack of joining an empty array of width plus one elements. It also appears in test code for generating strings of exact sizes, such as checking length limits with 'a'.repeat(maxLength + 1), which is both precise and self-documenting. Mind the edge cases that the specification defines sharply: repeat(0) returns an empty string, which is usually exactly right for a base case like zero depth; fractional counts are truncated toward zero, so repeat(2.9) repeats twice; and negative or infinite counts throw a RangeError rather than returning anything, so counts computed from data need validation or clamping with Math.max(0, n) first. For padding a value to a target width, prefer padStart() and padEnd(), which handle the subtraction and truncation for you; repeat() is the right tool when the repetition itself, not a target width, is the concept.

⚠️ Common Mistakes

Letting a computed count go negative: width - used can dip below zero on unexpectedly long content, and repeat() then throws a RangeError at runtime rather than returning an empty string. Clamp with Math.max(0, n) whenever the count is arithmetic on data.

Assuming fractional counts round: the count is truncated toward zero, so repeat(2.9) gives two copies, not three. Progress-bar math built on percentages should round explicitly with Math.round or Math.floor so the behavior is chosen, not inherited.

Generating enormous strings by accident: repeat() multiplies length, so a kilobyte string repeated a million times asks for a gigabyte and throws or grinds the process. Validate counts that arrive from user input or network data; unbounded repeat() on request data is a denial-of-service vector.

Expecting the original string to change: repeat() returns a new string; sep.repeat(3) as a bare statement does nothing, a recurring surprise with every immutable string method.

Rebuilding what padStart()/padEnd() already do: computing the deficit and repeating a pad character by hand duplicates padEnd(width) with more code and more edge cases, such as forgetting the clamp when the content exceeds the width.

Assuming visual width equals repetitions: repeating a full-width CJK character or an emoji produces a string whose rendered width differs from its length, so box-drawing and alignment based on repeat counts can look wrong in terminals despite correct code-unit math.

✅ Best Practices

Clamp or validate computed counts, as in char.repeat(Math.max(0, width - text.length)), so edge cases degrade to empty strings instead of throwing RangeError.

Cache repeated separators that are used many times, for example building a table border once and reusing it per row, rather than regenerating it inside the row loop.

Use unit.repeat(depth) for nesting indentation, keeping the indent unit in one named constant so the whole codebase agrees on two-space versus four-space output.

Round percentage-driven counts explicitly in progress bars, and derive the empty portion as total minus filled so the two segments always sum to the intended width.

Prefer padStart()/padEnd() when the goal is a target width and repeat() when the goal is N copies; picking the matching primitive removes arithmetic and its off-by-one risks.

Bound any repeat count that originates outside your code, both to prevent runaway allocation and to keep output layouts within sane limits.

⚡ Performance Notes

repeat() allocates one result string of exactly source length times count, and engines implement it with doubling-style copying, so the work is proportional to the output size, not to the count as a loop of appends would be. That makes it strictly better than concatenating in a loop, which creates intermediate strings, and better than the legacy Array(n + 1).join(unit) trick, which allocates a throwaway array. The only real hazard is output magnitude: length multiplies, and engines cap string sizes (on the order of a gigabyte in V8, with a hard specification ceiling of 2 to the 53rd minus 1 code units), so unvalidated counts can throw RangeError or exhaust memory. For building tables and bars, generating a full-width string once and slicing pieces from it can beat many small repeat() calls, but at typical console-output scales every approach is instantaneous; choose the clearest.

🌍 Real World Example

Text Formatting and Visual Elements

Four console-formatting utilities. printSection() builds a separator rule with '='.repeat and centers the title by repeating spaces for half the leftover width, the quickest way to produce readable CLI report headers. printTree() indents each node with ' '.repeat(depth), letting the repetition count mirror the recursion depth exactly. progressBar() converts a percentage into filled and empty block characters whose counts always sum to the bar width, the standard text progress indicator. generateLorem() manufactures placeholder text by over-repeating a phrase and trimming to the requested word count with split and slice, a handy trick for populating mock layouts and tests.

// Create a visual separator for console output
function printSection(title) {
  const width = 50;
  const separator = '='.repeat(width);
  const padding = ' '.repeat(Math.floor((width - title.length) / 2));
  console.log(separator);
  console.log(padding + title);
  console.log(separator);
}

printSection('Report');
// ==================================================
//                      Report
// ==================================================

// Generate tree-like indentation for nested structures
function printTree(node, depth = 0) {
  const indent = '  '.repeat(depth);
  const prefix = depth > 0 ? indent + '├─ ' : '';
  console.log(prefix + node.name);
  if (node.children) {
    node.children.forEach(child => printTree(child, depth + 1));
  }
}

// Create a simple text progress bar
function progressBar(percent, width = 30) {
  const filled = Math.round(width * percent / 100);
  const empty = width - filled;
  return '[' + '█'.repeat(filled) + '░'.repeat(empty) + '] ' + percent + '%';
}

console.log(progressBar(75)); // [██████████████████████░░░░░░░░] 75%

// Generate placeholder text
function generateLorem(words) {
  const lorem = 'Lorem ipsum dolor sit amet ';
  return lorem.repeat(Math.ceil(words / 5)).split(' ').slice(0, words).join(' ');
}

console.log(generateLorem(10));

Related Methods