JavaScript String [Symbol.iterator]() Method

Beginner
⏱️ 10 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Instance method

What You’ll Learn

String.prototype[Symbol.iterator]() makes strings iterable by yielding Unicode code points (same API as MDN String.prototype[Symbol.iterator]()). Learn for...of and spread, why surrogate pairs stay together, when emoji clusters still split, manual next(), five examples, and try-it labs.

01

Kind

Instance method

02

Returns

Iterator

03

Yields

Code points

04

Used by

for...of / spread

05

Mutates?

No

06

Baseline

Widely available

Introduction

Strings implement the iterable protocol through [Symbol.iterator](). That is why you can write for (const ch of str) or [...str] and walk the text one Unicode code point at a time.

You almost never call the method yourself. Loops and spread call it for you. Call it manually when you want fine-grained control with iterator.next().

💡
Beginner tip

Prefer for...of over for (let i = 0; i < str.length; i++) when you care about full characters (including many emoji), not raw UTF-16 units.

This page is part of JavaScript String Methods. Related topics include codePointAt() and charAt().

Understanding [Symbol.iterator]()

str[Symbol.iterator]() returns a new iterator object. Each next() call yields the next Unicode code point as a string.

  • Makes strings work with for...of, spread, and Array.from.
  • Iterates by code points β€” surrogate pairs stay as one value.
  • Grapheme clusters (skin tones, ZWJ families) may still yield multiple values.
  • Does not change the original string.

📝 Syntax

General form of String.prototype[Symbol.iterator]:

JavaScript
string[Symbol.iterator]()

Parameters

None.

Return value

A new iterable iterator object that yields the Unicode code points of the string as individual strings.

Exceptions

None for normal string values.

Common patterns

JavaScript
for (const ch of "Hi") { /* "H", "i" */ }

[..."𝐀"];                    // ["𝐀"]  β€” one code point (surrogate pair)

const it = "AB"[Symbol.iterator]();
it.next();                   // { value: "A", done: false }
it.next();                   // { value: "B", done: false }
it.next();                   // { value: undefined, done: true }

⚡ Quick Reference

GoalCode
Loop code pointsfor (const ch of str) { ... }
Spread to array[...str]
Get the iteratorstr[Symbol.iterator]()
Step manuallyit.next()
One code point by indexstr.codePointAt(i)

🔍 At a Glance

Four facts to remember about String[Symbol.iterator]().

Returns
iterator

Call next() for values

Yields
code points

Not raw UTF-16 units

Auto-used
for...of

And spread / Array.from

Mutates
no

Read-only walk

📋 Iterator vs Index Access

for...of / iteratorcharAt / str[i]codePointAt
ReadsCode pointsUTF-16 code unitsCode point number
Emoji pairUsually one stepTwo unitsOne number
ReturnsStrings via next/loop1-unit stringNumber / undefined
Best forWalking the whole stringFixed indexesInspect one index

Examples Gallery

Examples follow MDN String[Symbol.iterator]() patterns. Use View Output or Try It Yourself for each case.

📚 Getting Started

MDN demos for calling the iterator and looping.

Example 1 — Basic Iterator Walk

MDN Try it demo: print characters until the first space.

JavaScript
const str = "The quick red fox jumped over the lazy dog's back.";

const iterator = str[Symbol.iterator]();
let theChar = iterator.next();

while (!theChar.done && theChar.value !== " ") {
  console.log(theChar.value);
  theChar = iterator.next();
}
// "T"
// "h"
// "e"
Try It Yourself

How It Works

next() returns { value, done }. The loop stops at the first space without consuming the rest of the sentence.

Example 2 — for...of (Usual Way)

MDN demo: you seldom call the method β€” for...of does it.

JavaScript
const str = "A\uD835\uDC68B\uD835\uDC69C\uD835\uDC6A";

for (const v of str) {
  console.log(v);
}
// "A"
// "\uD835\uDC68"  (mathematical italic capital A)
// "B"
// "\uD835\uDC69"
// "C"
// "\uD835\uDC6A"
Try It Yourself

How It Works

Each special letter is a surrogate pair. Indexing with str[1] would see half a character; for...of yields the full letter.

🔧 Control & Unicode Details

Manual next(), grapheme splits, and spread.

Example 3 — Manual next()

MDN demo: hand-roll the iterator for maximum control.

JavaScript
const str = "A\uD835\uDC68";

const strIter = str[Symbol.iterator]();

console.log(strIter.next().value); // "A"
console.log(strIter.next().value); // "\uD835\uDC68"
Try It Yourself

How It Works

Useful when you want to pause, peek, or stop early without a full loop.

Example 4 — Grapheme Clusters Can Split

MDN note: code points are not always β€œwhat you see as one emoji.”

JavaScript
// Skin tone modifier
console.log([..."πŸ‘‰πŸΏ"]);
// ['πŸ‘‰', '🏿']

// ZWJ family sequence
console.log([..."πŸ‘¨β€πŸ‘¦"]);
// ['πŸ‘¨', '‍', 'πŸ‘¦']
Try It Yourself

How It Works

Surrogate pairs stay together, but modifiers and zero-width joiners are separate code points. For β€œuser-perceived characters,” you need a grapheme library β€” not only the string iterator.

Example 5 — Spread vs charAt

Practical compare: spread uses the iterator; charAt does not.

JavaScript
const s = "𝐀"; // mathematical bold A (surrogate pair)

console.log(s.length);           // 2  (UTF-16 units)
console.log(JSON.stringify([...s]));      // ["𝐀"]
console.log(JSON.stringify(s.charAt(0))); // half of the pair
console.log(Array.from(s).join("-"));     // "𝐀"
Try It Yourself

How It Works

length counts UTF-16 units. Spread and Array.from use [Symbol.iterator], so they see one full character.

🎯 Common Use Cases

  • Loop characters safelyfor...of over mixed ASCII + emoji text.
  • Build arrays of code points[...str] or Array.from(str).
  • Early-exit scans — manual next() until a delimiter.
  • Not grapheme clustering — skin tones / ZWJ may still split.
  • Not UTF-16 indexing — use charAt / indexes when you need units.

🧠 How String Iteration Works

1

Get the iterator

for...of / spread call str[Symbol.iterator]().

Start
2

Read the next code point

If a high surrogate is paired, both units become one string.

Yield
3

Repeat until done

next() returns { done: true } at the end.

Loop
4

Original string unchanged

Iteration only reads values.

📝 Notes

  • You rarely call [Symbol.iterator] directly β€” prefer for...of.
  • Surrogate pairs are preserved; grapheme clusters may still split.
  • str.length counts UTF-16 units, not iterator steps.
  • Lone surrogates yield as single broken units β€” pair with isWellFormed when needed.
  • Each call to [Symbol.iterator]() creates a new iterator from the start.

Browser & Runtime Support

String.prototype[Symbol.iterator]() is Baseline Widely available β€” supported across modern browsers since September 2015.

Baseline · Widely available

String[Symbol.iterator]()

Safe for production in browsers and runtimes (Node.js, Deno, Bun). Powers for...of and spread on strings.

Universal Widely available
Google Chrome Supported · Desktop & Mobile
Full support
Mozilla Firefox Supported · Desktop & Mobile
Full support
Apple Safari Supported · macOS & iOS
Full support
Microsoft Edge Supported · Chromium
Full support
Internet Explorer No native support · Use a polyfill
Polyfill
Opera Supported · Modern versions
Full support
Samsung Internet Supported · Android
Full support
Bun Supported · JavaScript runtime
Supported
Deno Supported · JavaScript runtime
Supported
Node.js Supported · Server runtime
Supported
Android WebView Supported · Modern WebView
Full support
[Symbol.iterator]() Excellent

Bottom line: Use for...of or spread to walk Unicode code points. Call [Symbol.iterator]() only when you need manual next() control.

Conclusion

String.prototype[Symbol.iterator]() is why strings work with modern iteration syntax. Prefer for...of for everyday loops, and remember that code points are safer than UTF-16 indexes for emoji β€” but not always identical to visible graphemes.

Continue with codePointAt(), charAt(), or the String methods hub.

💡 Best Practices

✅ Do

  • Use for...of to walk characters / code points
  • Use spread when you need an array of code points
  • Call the iterator manually for early-exit scans
  • Pair with codePointAt when you need numbers
  • Remember grapheme clusters may need extra libraries

❌ Don’t

  • Assume every emoji is a single iterator step
  • Use str[i] loops for emoji-heavy text
  • Equate length with the number of for...of steps
  • Forget each [Symbol.iterator]() call starts over
  • Call the method when for...of already does the job

Key Takeaways

Knowledge Unlocked

Five things to remember about String[Symbol.iterator]()

Iterable by code points β€” for...of usually calls it for you.

5
Core concepts
🌐 02

Yields

code points

Unicode
🔄 03

Used by

for...of

Syntax
😀 04

Clusters

may split

Emoji
05

Mutates

no

Immutable

❓ Frequently Asked Questions

It returns a string iterator that yields each Unicode code point as a string. That makes strings iterable for for...of, spread (...), Array.from, and similar APIs.
Rarely. for...of and the spread syntax call it automatically. Call it manually when you want step-by-step control with next().
str[i] and charAt(i) read UTF-16 code units. The iterator yields full Unicode code points, so a single emoji made of a surrogate pair is one step, not two.
Surrogate pairs stay together as one code point. Grapheme clusters (emoji + skin tone, ZWJ sequences) can still split into multiple code points.
An object { value, done }. value is the next code-point string (or undefined when done is true).
No. It only creates an iterator that reads the string. Strings are immutable.
Did you know?

Before Symbol.iterator, people often wrote for (var i = 0; i < str.length; i++) and accidentally split emoji. The iterable protocol is why modern loops β€œjust work” for most Unicode letters β€” as long as you remember grapheme clusters are a separate problem.

More String Methods

Return to the hub for slice, trim, replace, and more.

String methods hub →

About the author

Mari Selvan M P
Mari Selvan M P πŸ”—

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful