Strings are primitive values in JavaScript and immutable. That is, string-related operations always produce new strings and never change existing strings.
Literals for strings:
const str1 = 'Don\'t say "goodbye"'; // string literal
const str2 = "Don't say \"goodbye\""; // string literals
assert.equal(
`As easy as ${123}!`, // template literal
'As easy as 123!',
);
Backslashes are used to:
- Escape literal delimiters (first 2 lines of previous example)
- Insert special characters:
\\
inserts a backslash\n
inserts a newline\r
inserts a carriage return\t
inserts a tab
Inside a String.raw
tagged template (line A), backslashes are treated as normal characters:
assert.equal(
String.raw`\ \n\t`, // (A)
'\\ \\n\\t',
);
Convertings values to strings:
> String(undefined)
'undefined'
> String(null)
'null'
> String(123.45)
'123.45'
> String(true)
'true'
Copying parts of a string
// There is no type for characters;
// reading characters produces strings:
const str3 = 'abc';
assert.equal(
str3[2], 'c' // no negative indices allowed
);
assert.equal(
str3.at(-1), 'c' // negative indices allowed
);
// Copying more than one character:
assert.equal(
'abc'.slice(0, 2), 'ab'
);
Concatenating strings:
assert.equal(
'I bought ' + 3 + ' apples',
'I bought 3 apples',
);
let str = '';
str += 'I bought ';
str += 3;
str += ' apples';
assert.equal(
str, 'I bought 3 apples',
);
Some Unicode code points (roughly: characters) take up two JavaScript characters:
assert.equal(
'π'.length, 2
);
Safe ways of processing Unicode code points:
assert.deepEqual(
Array.from('πXπ'), [ 'π', 'X', 'π' ]
);
assert.deepEqual(
[...'πXπ'], [ 'π', 'X', 'π' ]
);
for (const codePoint of 'πXπ') {
console.log(codePoint);
}
// Output:
// 'π'
// 'X'
// 'π'
In constrast, .split('')
splits into JavaScript characters:
assert.deepEqual(
'πXπ'.split(''),
['\uD83D', '\uDE42', 'X', '\uD83D', '\uDE42']
);
Note that the real Unicode characters are called grapheme clusters and can comprise multiple code points.
Finding substrings:
> 'abca'.includes('a')
true
> 'abca'.startsWith('ab')
true
> 'abca'.endsWith('ca')
true
> 'abca'.indexOf('a')
0
> 'abca'.lastIndexOf('a')
3
Splitting and joining:
assert.deepEqual(
'a, b,c'.split(/, ?/),
['a', 'b', 'c']
);
assert.equal(
['a', 'b', 'c'].join(', '),
'a, b, c'
);
Padding and trimming:
> '7'.padStart(3, '0')
'007'
> 'yes'.padEnd(6, '!')
'yes!!!'
> '\t abc\n '.trim()
'abc'
> '\t abc\n '.trimStart()
'abc\n '
> '\t abc\n '.trimEnd()
'\t abc'
Repeating and changing case:
> '*'.repeat(5)
'*****'
> '= b2b ='.toUpperCase()
'= B2B ='
> 'ΞΞΞ'.toLowerCase()
'Ξ±Ξ²Ξ³'