string
In JavaScript, string is a primitive type that represents text as an immutable sequence of 16-bit UTF-16 code units. It’s one of JavaScript’s primitive types, distinct from the String wrapper object, whose prototype supplies its methods:
> "Hello, Ada!"
'Hello, Ada!'
> typeof "Hello, Ada!"
'string'
Strings are immutable, so methods such as .toUpperCase() return a new string and leave the original unchanged. Two strings compare by value, which means === and Object.is() both return true when they hold the same code units in the same order.
string Literals and typeof
A string literal uses double quotes, single quotes, or backticks. Single and double quotes behave the same, and choosing one avoids escaping the other inside the text. Backticks create a template literal, which can span several lines and embed expressions with ${}. All three forms produce the same type:
> const city = "Lisbon";
undefined
> "Ada said 'hi'"
"Ada said 'hi'"
> `Welcome to ${city}!`
'Welcome to Lisbon!'
> `line one
… line two`
'line one\nline two'
> typeof `${city}`
'string'
Escape sequences such as \n, \t, and \u{1F600} work in all three forms. The empty string "" is a valid string and is falsy.
Converting to string
String(value) converts explicitly, and a template literal does the same conversion when it embeds a value. A symbol converts only explicitly, with String() or its .toString() method. A template literal or the + operator throws a TypeError for one:
> String(42)
'42'
> String(null)
'null'
> String([1, 2, 3])
'1,2,3'
> String({})
'[object Object]'
> `${undefined}`
'undefined'
> String(Symbol("id"))
'Symbol(id)'
> `${Symbol("id")}`
Uncaught TypeError: Cannot convert a Symbol value to a string
Arrays join their elements with commas, and plain objects become "[object Object]" unless they define their own .toString() method.
Common string Gotchas
Assigning to an index of a primitive string doesn’t change it:
> const word = "cat";
undefined
> word[0] = "b";
'b'
> word
'cat'
The REPL runs in sloppy mode, where the assignment is silently ignored. In strict mode, it throws a TypeError. To change a string, build a new one, for example with "b" + word.slice(1).
The + operator concatenates as soon as one operand is a string, while -, *, and / convert both operands to numbers through type coercion:
> "5" + 1
'51'
> "5" - 1
4
> 1 + 2 + "3"
'33'
Evaluation runs left to right, so 1 + 2 becomes 3 before the string joins in.
The .length property counts UTF-16 code units, not visible characters. Characters outside the Basic Multilingual Plane, such as most emoji, take two code units each. The examples below write the emoji as escape sequences:
> const smile = "\u{1F600}";
undefined
> smile.length
2
> [...smile].length
1
> "\u{1F44D}\u{1F3FD}".length
4
Spread syntax and for...of iterate over code points instead of code units, so [...smile] holds one element. A thumbs-up emoji with a skin-tone modifier is two code points that render as one symbol, so even a code point count doesn’t match what a reader sees. Intl.Segmenter, part of ECMA-402 since its 2022 edition, splits text into those visible units, called grapheme clusters.
Indexing into a string returns a single code unit, which can be half of a surrogate pair:
> "\u{1F600}"[0]
'\ud83d'
> "\u{1F600}".codePointAt(0)
128512
Have a question about this? Mentor AI can show you examples, compare related terms, and point you to tutorials.
By Leodanis Pozo Ramos • Updated Nov. 4, 2026