Objeto `String`
Este artigo explica o objeto String.
A explicação abrange tudo, desde o básico até técnicas avançadas, incluindo armadilhas relacionadas ao Unicode e expressões regulares, passo a passo e de forma fácil de entender.
YouTube Video
Objeto String
Strings em JavaScript são um dos tipos mais utilizados no desenvolvimento diário.
Diferença entre strings primitivas e objetos String
Strings primitivas (como "hello") se comportam de forma diferente de objetos wrapper como new String("hello"). Normalmente, você deve usar valores primitivos e há pouca necessidade de utilizar a forma de objeto.
1// Primitive string
2const a = "hello";
3
4// String wrapper object
5const b = new String("hello");
6
7console.log(typeof a); // "string"
8console.log(typeof b); // "object"
9console.log(a === b); // false — wrapper objects are not strictly equal
- Este código mostra a diferença de tipo entre um primitivo e um wrapper, e como se comportam em comparações estritas. Na maioria dos casos, evite usar
new String()e prefira valores primitivos.
Formas de criar strings (literais e literais de template)
Literais de template são úteis para embutir variáveis e criar strings de múltiplas linhas. Você pode inserir variáveis e avaliar expressões de forma intuitiva.
1const name = "Alice";
2const age = 30;
3
4// Template literal
5const greeting = `Name: ${name}, Age: ${age + 1}`;
6
7console.log(greeting); // "Name: Alice, Age: 31"
- Literais de template são altamente legíveis e ideais para construir strings complexas, incluindo multilinhas.
Métodos comuns (Busca e extração de substrings)
O objeto String possui muitos métodos básicos.
1const text = "Hello, world! Hello again.";
2
3// search
4console.log(text.indexOf("Hello")); // 0
5console.log(text.indexOf("Hello", 1)); // 13
6console.log(text.includes("world")); // true
7console.log(text.startsWith("Hello")); // true
8console.log(text.endsWith("again.")); // true
9
10// slice / substring
11console.log(text.slice(7, 12)); // "world"
12console.log(text.substring(7, 12)); // "world"
sliceesubstringsão semelhantes, mas tratam índices negativos de forma diferente.sliceinterpreta valores negativos como posições a partir do final. Seja claro/a sobre qual deles usar.
Dividindo e unindo (split / join)
É comum dividir uma string em um array para processá-la e, em seguida, uni-la novamente.
1const csv = "red,green,blue";
2const arr = csv.split(","); // ["red","green","blue"]
3
4console.log(arr);
5console.log(arr.join(" | ")); // "red | green | blue"
- Um padrão comum é usar
splitpara dividir uma string, processar o array resultante commapoufiltere depois usarjoinpara unificá-lo novamente.
Substituição e expressões regulares
replace substitui apenas a primeira ocorrência. Se quiser substituir todas as ocorrências, utilize o modificador g em uma expressão regular. Ao passar uma função como substituto, é possível fazer substituições dinâmicas.
1const s = "foo 1 foo 2";
2
3// replace first only
4console.log(s.replace("foo", "bar")); // "bar 1 foo 2"
5
6// replace all using regex
7console.log(s.replace(/foo/g, "bar")); // "bar 1 bar 2"
8
9// replace with function
10const r = s.replace(/\d+/g, (match) => String(Number(match) * 10));
11console.log(r); // "foo 10 foo 20"
- Com substituição dinâmica utilizando uma função, é possível escrever de forma concisa um código que analisa e transforma as correspondências.
Conversão de caixa e normalização
Para suporte e comparação multilíngue, além de toLowerCase e toUpperCase, a normalização Unicode (normalize) também é importante. Isso é especialmente necessário ao comparar caracteres acentuados.
1// Case conversion example:
2// "\u00DF" represents the German letter "ß".
3// In some locales, converting "ß" to uppercase becomes "SS".
4// JavaScript follows this behavior.
5console.log("\u00DF");
6console.log("\u00DF".toUpperCase()); // "SS"
7
8// Unicode normalization example:
9// "e\u0301" is "e" + a combining acute accent.
10// "\u00e9" is the precomposed character "é".
11// These two look the same but are different code point sequences.
12const a = "e\u0301";
13const b = "\u00e9";
14
15console.log(a === b); // false: different underlying code points
16console.log(a.normalize() === b.normalize()); // true: normalized to the same form
- Representações Unicode diferentes, como ligaduras e caracteres combinados, não serão iguais como estão, portanto use
normalize()antes de comparar.
Unicode e pontos de código (manipulando pares substitutos)
Strings JavaScript são sequências de unidades de código UTF-16, então alguns caracteres, como emojis, podem ocupar duas unidades para um único caractere. Para lidar com unidades reais de caracteres, utilize Array.from, o operador spread ou for...of.
1// Emoji composed with multiple code points:
2// "\u{1F469}" = woman, "\u{200D}" = Zero Width Joiner (ZWJ),
3// "\u{1F4BB}" = laptop. Combined, they form a single emoji: 👩💻
4const s = "\u{1F469}\u{200D}\u{1F4BB}";
5console.log(s);
6
7// Length in UTF-16 code units (not actual Unicode characters):
8// Because this emoji uses surrogate pairs + ZWJ, the length may be > 1.
9console.log("Length:", s.length);
10
11// Iterate by Unicode code points (ES6 for...of iterates code points):
12// Each iteration gives a full Unicode character, not UTF-16 units.
13for (const ch of s) {
14 console.log(ch);
15}
16
17// Convert to an array of Unicode characters:
18console.log(Array.from(s));lengthretorna o número de unidades de código, portanto pode não obter a contagem esperada com emojis ou ligaduras.for...ofeArray.fromlidam com algo próximo aos caracteres exibidos (clusters de grafemas), mas caso precise de um suporte completo a grafemas, considere utilizar uma biblioteca especializada.
Substituição segura com expressões regulares (ao trabalhar com entrada do usuário)
Se você esquecer de escapar a entrada do usuário ao incorporá-la em uma expressão regular, isso pode levar a comportamentos inesperados e vulnerabilidades. Sempre faça o escape da entrada do usuário antes de usá-la em um padrão.
1function escapeRegex(s) {
2 return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3}
4
5const userInput = "a+b";
6const pattern = new RegExp(escapeRegex(userInput), "g");
7console.log("a+b a+b".replace(pattern, "X")); // "X X"
- Não utilize strings dos usuários diretamente em expressões regulares; sempre faça o escape antes de montar a regex.
Dicas de desempenho: concatenação e templates
Ao concatenar muitas pequenas strings em sequência, inseri-las em um array e usar join pode ser mais eficiente. Por outro lado, templates strings são altamente legíveis e rápidas o suficiente na maioria dos casos.
1// concatenation in loop (less ideal)
2let s = "";
3for (let i = 0; i < 1000; i++) {
4 s += i + ",";
5}
6
7// using array + join (often faster for many pieces)
8const parts = [];
9for (let i = 0; i < 1000; i++) {
10 parts.push(i + ",");
11}
12const s2 = parts.join("");- Engines modernas do JavaScript são altamente otimizadas, então não há necessidade de se preocupar com desempenho para um pequeno número de concatenações. No entanto, se for necessário concatenar dezenas de milhares de vezes, o uso de
joinpode ser mais eficiente.
Técnicas práticas úteis: padding, trim e repeat
trim, padStart, padEnd e repeat são métodos convenientes que são especialmente úteis no processamento diário de strings. Eles são frequentemente usados em situações práticas, como formatar valores de entrada ou padronizar formatos de saída.
1console.log(" hello ".trim()); // "hello"
2console.log("5".padStart(3, "0")); // "005"
3console.log("x".repeat(5)); // "xxxxx"
- Estes métodos podem ser usados para normalizar entradas de formulário ou gerar saídas de largura fixa.
Comparação de strings (comparação local)
localeCompare é eficaz para comparar strings segundo a ordem do dicionário de diferentes idiomas. Você pode especificar opções de idioma e sensibilidade (como diferenciação de maiúsculas/minúsculas).
1console.log(
2 "\u00E4".localeCompare("z", "de")
3); // may be -1 or other depending on locale
4
5console.log(
6 "a".localeCompare("A", undefined, { sensitivity: "base" })
7); // 0
- Para comparações internacionalizadas, use
localeComparee especifique o locale e opções apropriadas.
Exemplo prático: convertendo uma linha CSV em um objeto (fluxo de trabalho prático)
Um caso de uso comum é analisar uma única linha CSV em um objeto usando uma combinação de split, trim e map. Para campos com aspas ou arquivos CSV complexos, use um analisador CSV dedicado.
1// simple CSV parse (no quotes handling)
2function parseCsvLine(line, headers) {
3 const values = line.split(",").map(v => v.trim());
4 const obj = {};
5 headers.forEach((h, i) => obj[h] = values[i] ?? null);
6 return obj;
7}
8
9const headers = ["name", "age", "city"];
10const line = " Alice , 30 , New York ";
11console.log(parseCsvLine(line, headers));
12// { name: "Alice", age: "30", city: "New York" }
- Este método funciona para CSVs simples, mas esteja ciente de que não pode lidar com casos em que uma vírgula está dentro de um campo entre aspas.
Armadilhas comuns
Existem especificações e comportamentos facilmente ignorados ao lidar com strings em JavaScript. Para evitar bugs inesperados, é importante ter os seguintes pontos em mente.
- Usar
new String()pode levar a resultados incorretos em verificações ou comparações de tipo. Na maioria dos casos, tipos de string primitivos são suficientes. - Em Unicode, um único caractere visível pode ser composto de várias unidades de código. Sendo assim, o valor retornado por
lengthpode não corresponder ao número real de caracteres exibidos. - Ao incorporar entradas de usuário em uma expressão regular, sempre escape antes.
String.prototype.replace()substitui apenas a primeira correspondência por padrão. Se você quiser substituir todas as ocorrências, use a flag/gem sua expressão regular.- Strings são imutáveis, por isso as operações sempre retornam uma nova string. É importante sempre atribuir o valor retornado.
Resumo
Mesmo que strings em JavaScript possam parecer simples, é importante entender suas características em relação ao Unicode e à imutabilidade. Ao dominar o básico, você pode aumentar muito a confiabilidade e legibilidade do seu processamento de strings.
Você pode acompanhar o artigo acima usando o Visual Studio Code em nosso canal do YouTube. Por favor, confira também o canal do YouTube.