6. As cadeias de caracteres
As cadeias de caracteres do JavaScript são muito semelhantes às do PHP.

6.1. script [str-01]
A primeira coisa a entender é que, uma vez criada, uma string não pode mais ser modificada. Existem vários métodos para gerar uma nova string a partir da string inicial, mas esta permanece sempre inalterada. Além disso, uma string de caracteres pode ser de dois tipos:
- [string] quando inicializada com uma string literal;
- [object] quando é criada como instância da classe [String];
''use strict';
// as cadeias de caracteres são somente de leitura (não podem ser modificadas)
// uma sequência de caracteres
const chaîne1 = "abcd ";
// tipo
console.log("typeof(chaîne1)=", typeof (chaîne1));
// caractere nº 2
console.log("chaîne1[2]=", chaîne1[2]);
// gera um erro
chaîne1[2] = "0";
Execução
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Temp\19-09-01\javascript\strings\str-01.js"
typeof(chaîne1)= string
chaîne1[2]= c
c:\Temp\19-09-01\javascript\strings\str-01.js:1
TypeError: Cannot assign to read only property '2' of string 'abcd '
at Object.<anonymous> (c:\Temp\19-09-01\javascript\strings\str-01.js:12:12)
at Generator.next (<anonymous>)
6.2. script [str-02]
Este script mostra que é possível construir uma sequência de caracteres de duas maneiras.
''use strict';
// as cadeias de caracteres podem ser de dois tipos
// uma cadeia literal
const chaîne1 = "abcd ";
// tipo
console.log("typeof(chaîne1)=", typeof (chaîne1));
// instância de String
const chaîne2 = new String("xyzt");
// tipo
console.log("typeof(chaîne2)=", typeof (chaîne2));
// outra forma de escrita (sem new) – tipo [string] e não [object]
const chaîne3 = String("12 34");
// tipo
console.log("typeof(chaîne3)=", typeof (chaîne3));
// o tipo [string] e o tipo [object] oferecem os mesmos métodos, os da classe String
console.log("chaîne1.length=", chaîne1.length);
console.log("chaîne2.length=", chaîne2.length);
Comentários
- linha 6: o método usual de definição de uma sequência de caracteres. [chaîne1] será do tipo [string];
- linha 10: é possível construir uma cadeia de caracteres usando o construtor da classe [String]. [chaîne2] será do tipo [object];
Execução
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\strings\str-02.js"
typeof(chaîne1)= string
typeof(chaîne2)= object
typeof(chaîne3)= string
chaîne1.length= 5
chaîne2.length= 4
O tipo [string] dispõe dos métodos da classe [String].
6.3. script [str-03]
Este script mostra uma sequência específica com interpolação de variáveis.
'use strict';
// cadeia
const chaîne = "Introduction à Javascript par l'exemple";
// cadeia com interpolação de variáveis
const str = `[${chaîne}].substr(3, 2)=` + chaîne.substr(3, 2)
console.log(str);
Comentários
- linha 6: é possível ter cadeias de caracteres contendo expressões ${variável}, que são substituídas pelo valor da variável. Trata-se da mesma lógica das variáveis $ nas cadeias de caracteres PHP. Observe a notação dessa sequência: ela é delimitada por “backstick” ou apóstrofo invertido (AltGr-7 em um teclado francês);
Execução
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Temp\19-09-01\javascript\strings\tempCodeRunnerFile.js"
[Introduction à Javascript par l'exemple].substr(3, 2)=ro
6.4. script [str-04]
A string com interpolação de variáveis continua sendo insuficiente. De fato, não é possível substituir a variável pela expressão na forma ${variável}. Para quem já programou em C, não há nada como as funções [printf, sprintf] para escrever ou construir strings formatadas. Centenas de desenvolvedores criaram milhares de pacotes JavaScript, formando um ecossistema imenso. Quando surge uma necessidade que não é atendida nativamente pelo JavaScript, é hora de procurar um pacote que a satisfaça. Para isso, utilizamos o gerenciador de pacotes [npm]. Ele possui uma opção [search] que permite procurar uma sequência de caracteres na descrição dos pacotes. [npm] retorna a lista de pacotes que atendem à pesquisa. Portanto, vamos procurar a sequência [sprintf] na descrição dos pacotes:

- na coluna [4], as palavras-chave dos pacotes da coluna [3];
- na coluna [5], a descrição dos pacotes da coluna [3];
O próximo passo é acessar o site da ferramenta [npm], [https://www.npmjs.com/] e ler a descrição dos pacotes:

No [3], examinamos a lista de pacotes e escolhemos um.

Na descrição do pacote, encontram-se as informações para instalá-lo e utilizá-lo:

Instalamos o pacote [sprintf-js] em um terminal do [VSCode]:

Essa instalação modificará o arquivo [package.json] localizado na raiz da pasta [javascript] [2]:

Vemos acima que o pacote foi instalado nos [dependencies], ou seja, nos pacotes necessários para a execução do projeto. Vale lembrar que os pacotes necessários são colocados em [devDependencies] apenas durante o desenvolvimento do projeto. Eles não são utilizados durante a execução. Essa diferença é importante quando é necessário criar a versão final do projeto para sua entrada em produção. Existem ferramentas para:
- reunir todos os arquivos jS necessários para a execução em um único arquivo. Os pacotes [devDependencies], portanto, não são incluídos nesse arquivo final;
- minimizá-lo, ou seja, reduzir seu tamanho ao mínimo possível. Para isso, por exemplo, todos os comentários são removidos;
- “ofuscar” o código para torná-lo difícilmente compreensível. Por exemplo, as variáveis taxa, salário e imposto serão substituídas pelas variáveis a, b e c;
- realizar outras otimizações;
Essa otimização do arquivo final de um projeto jS é utilizada na programação web. Um aplicativo web pode depender de um grande número de arquivos JavaScript. O carregamento desses arquivos por um navegador pode retardar a exibição da primeira página do aplicativo. A otimização anterior visa melhorar esse tempo de carregamento. Se o tempo de carregamento for considerado muito longo pelos usuários, a aplicação não será utilizada.
Agora que dispomos do pacote [sprintf-js], precisamos utilizá-lo. Trata-se do script [str-04]:
'use strict';
// uso de um pacote externo para disponibilizar a função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = "Introduction à Javascript par l'exemple";
// método
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));
Com o ECMAScript 6, usamos a palavra-chave [import] para importar um objeto exportado por um pacote. Para saber o que o pacote exporta, podemos consultar seu código:

- no [1], clique com o botão direito do mouse no pacote importado;
- no [2], queremos ver a definição;
- em [3-4], vemos que o pacote exporta uma função chamada [sprintf];
A função [sprintf] do pacote [sprintf-js] é importada com a instrução:
import { sprintf } from 'sprintf-js';
O código completo:
'use strict';
// uso de um pacote externo para disponibilizar a função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = "Introduction à Javascript par l'exemple";
// método
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));
produz os seguintes resultados:
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\strings\str-04.js"
c:\Temp\19-09-01\javascript\strings\str-04.js:3
import { sprintf } from 'sprintf-js';
^
SyntaxError: Unexpected token {
at new Script (vm.js:79:7)
at createScript (vm.js:251:10)
at Object.runInThisContext (vm.js:303:10)
at Module._compile (internal/modules/cjs/loader.js:657:28)
Na linha 3, a instrução [import] não foi compreendida. Isso se deve ao fato de que a versão 10.15.1 do [node.js] utilizada neste curso (setembro de 2019) ainda não segue a norma ECMAScript para a importação de pacotes chamados módulos. Em 2019, o [node.js] segue um padrão de módulos denominado CommonJS. A integração dos módulos ECMAScript pelo [node.js] está prevista para 2020. Mais uma vez, os desenvolvedores se empenharam e criaram pacotes que permitem o uso dos módulos ES6 com o [node.js] já a partir de agora (2019).
Vamos utilizar um pacote chamado [esm] (Módulos ECMAScript). Vamos instalá-lo em um terminal do projeto [javascript]:

No [4], percebemos que a instalação do pacote [esm] [1-3] alterou o arquivo [javascript/package.json].
Ainda não terminamos. Para que o módulo [esm] seja utilizado pelo [node.js], é necessário executá-lo com o argumento [-r esm].
Portanto, alteramos a configuração da extensão [Code Runner] do [VSCode]:


No [11], adicionamos o argumento [-r esm] e salvamos (Ctrl-S) a configuração.
Agora, podemos executar o script [str-04]:
'use strict';
// uso de um pacote externo para disponibilizar a função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = "Introduction à Javascript par l'exemple";
// método substr
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));

6.5. script [str-05]
Veja o que diz a documentação sobre a função [sprintf]:
Os placeholders na string de formato são marcados por % e são seguidos por um ou mais desses elementos, nesta ordem:
- Um número opcional seguido pelo sinal $, que seleciona qual índice de argumento deve ser usado para o valor. Se não for especificado, os argumentos serão colocados na mesma ordem que os placeholders na string de entrada.
- Um sinal de mais (+) opcional que força a precedência do resultado com um sinal de mais ou de menos em valores numéricos. Por padrão, apenas o sinal de menos (-) é usado em números negativos.
- Um especificador de preenchimento opcional que indica qual caractere usar para preenchimento (se especificado). Os valores possíveis são 0 ou qualquer outro caractere precedido por uma ' (aspas simples). O padrão é preencher com espaços.
- Um sinal de menos (-) opcional, que faz com que o sprintf alinhe à esquerda o resultado desse marcador de posição. O padrão é alinhar o resultado à direita.
- Um número opcional que indica quantos caracteres o resultado deve ter. Se o valor a ser retornado for menor que esse número, o resultado será preenchido. Quando usado com o especificador de tipo j (JSON), o comprimento do preenchimento especifica o tamanho da tabulação usada para recuo.
- Um modificador de precisão opcional, composto por um . (ponto) seguido por um número, que indica quantos dígitos devem ser exibidos para números de ponto flutuante. Quando usado com o especificador de tipo g, ele especifica o número de dígitos significativos. Quando usado em uma string, faz com que o resultado seja truncado.
- Um especificador de tipo que pode ser qualquer um dos seguintes:
- % — retorna o caractere % literal
- b — retorna um inteiro como número binário
- c — retorna um inteiro como o caractere com esse valor
- d ou i — retorna um inteiro como um número decimal com sinal
- e — retorna um número de precisão flutuante na notação científica
- u — retorna um inteiro como um número decimal sem sinal
- f — retorna um valor float tal como está; consulte as notas sobre precisão acima
- g — retorna um float tal como está; consulte as notas sobre precisão acima
- o — retorna um inteiro como número octal
- s — retorna uma string tal como está
- t — retorna verdadeiro ou falso
- T — retorna o tipo do argumento1
- v — retorna o valor primitivo do argumento especificado
- x — retorna um inteiro como número hexadecimal (letras minúsculas)
- X — retorna um inteiro como um número hexadecimal (em maiúsculas)
- j — retorna um objeto ou array JavaScript como uma string codificada em JSON
O script [script-05] implementa alguns desses formatos:
'use strict';
// uso de um pacote externo para disponibilizar a função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = "Javascript";
// cadeias de caracteres
console.log(sprintf("[%s, %%s]=>[%s]", chaîne, chaîne));
console.log(sprintf("[%s, %%20s]=>[%20s]", chaîne, chaîne));
console.log(sprintf("[%s, %%-20s]=>[%-20s]", chaîne, chaîne));
// inteiros
console.log(sprintf("[%d, %%d]=>[%d]", 10, 10));
console.log(sprintf("[%d, %%4d]=>[%4d]", 10, 10));
console.log(sprintf("[%d, %%-4d]=>[%-4d]", 10, 10));
console.log(sprintf("[%d, %%04d]=>[%04d]", 10, 10));
// números reais
console.log(sprintf("[%f, %%f]=>[%f]", -10.5, -10.5));
console.log(sprintf("[%f, %%10.2f]=>[%10.2f]", -10.5, -10.5));
console.log(sprintf("[%f, %%-10.2f]=>[%-10.2f]", -10.5, -10.5));
console.log(sprintf("[%f, %%010.3f]=>[%010.3f]", -10.5, -10.5));
// json
console.log(sprintf("personne (%%j)=%j", { nom: "mathieu", âge: 34 }));
// tipo
console.log(sprintf("type personne (%%T)=%T", { nom: "mathieu", âge: 34 }));
// booleano
console.log(sprintf("booléen (%%t)=%t", 4 === 4));
Execução
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\strings\str-05.js"
[Javascript, %s]=>[Javascript]
[Javascript, %20s]=>[ Javascript]
[Javascript, %-20s]=>[Javascript ]
[10, %d]=>[10]
[10, %4d]=>[ 10]
[10, %-4d]=>[10 ]
[10, %04d]=>[0010]
[-10.5, %f]=>[-10.5]
[-10.5, %10.2f]=>[ -10.50]
[-10.5, %-10.2f]=>[-10.50 ]
[-10.5, %010.3f]=>[-00010.500]
personne (%j)={"nom":"mathieu","âge":34}
type personne (%T)=object
booléen (%t)=true
6.6. script [str-06]
O script [str-06] apresenta alguns métodos da classe [String] que também podem ser utilizados no tipo [string]:
'use strict';
// uso de um pacote externo para disponibilizar a função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = " Introduction à Javascript ";
// alguns métodos
// substr(10,2): 2 caracteres a partir do 10º
console.log(sprintf("[%s].substr(10,2)=[%s]", chaîne, chaîne.substr(10, 2)));
// trim: remoção de espaços em branco no início e no final da string (espaço em branco = \b \t \r \n \f)
console.log(sprintf("[%s].trim()=[%s]", chaîne, chaîne.trim()));
// toLowerCase: conversão para letras minúsculas
console.log(sprintf("[%s].toLowerCase=[%s]", chaîne, chaîne.toLowerCase()));
// toUpperCase: conversão para maiúsculas
console.log(sprintf("[%s].toUpperCase=[%s]", chaîne, chaîne.toUpperCase()));
// indexOf: posição de uma subcadei a procurada na cadeia; -1 se a subcadeia não existir
console.log(sprintf("[%s].indexOf('Java')=[%s]", chaîne, chaîne.indexOf('Java')));
console.log(sprintf("[%s].trim().indexOf('abcd')=[%s]", chaîne, chaîne.indexOf('abcd')));
// includes: verdadeiro se a sequência procurada estiver na sequência
console.log(sprintf("[%s].includes('Java')=[%s]", chaîne, chaîne.includes('Java')));
// length: comprimento da string — não é um método, mas uma propriedade
console.log(sprintf("[%s].length=[%s]", chaîne, chaîne.length));
// slice (7,10): sequência dos caracteres do 7º ao 9º
console.log(sprintf("[%s].slice(7,10)=[%s]", chaîne, chaîne.slice(7, 10)));
// match: procura uma expressão na sequência de caracteres — essa expressão pode ser uma expressão regular
// /intro/i: expressão regular que designa a sequência [intro] em maiúsculas ou minúsculas
// retorna a sequência encontrada
console.log(sprintf("[%s].match(/intro/i)=[%s]", chaîne, chaîne.match(/intro/i)));
// substituir: substitui a string1 pela string2 na string
// substitui a primeira ocorrência de i por x
console.log(sprintf("[%s].replace('i','x')=[%s]", chaîne, chaîne.replace('i', 'x')));
// substitui todas as ocorrências de i por x
// /i/g é uma expressão regular que designa todas (g) as ocorrências de i
console.log(sprintf("[%s].replace(/i/g,'x')=[%s]", chaîne, chaîne.replace(/i/g, 'x')));
// split: divide a cadeia em palavras separadas pelo parâmetro de divisão
// retorna a matriz dessas palavras
// /\s*/: palavras separadas por zero ou mais espaços
console.log(sprintf("[%s].split(/\\s*/)=[%s]", chaîne, chaîne.split(/\s*/)));
// /\s+/: palavras separadas por um ou mais espaços
console.log(sprintf("[%s].split(/\\s+/)=[%s]", chaîne, chaîne.split(/\s+/)));
Execução
[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\strings\str-06.js"
[ Introduction à Javascript ].substr(10,2)=[ti]
[ Introduction à Javascript ].trim()=[Introduction à Javascript]
[ Introduction à Javascript ].toLowerCase=[ introduction à javascript ]
[ Introduction à Javascript ].toUpperCase=[ INTRODUCTION À JAVASCRIPT ]
[ Introduction à Javascript ].indexOf('Java')=[17]
[ Introduction à Javascript ].trim().indexOf('abcd')=[-1]
[ Introduction à Javascript ].includes('Java')=[true]
[ Introduction à Javascript ].length=[28]
[ Introduction à Javascript ].slice(7,10)=[duc]
[ Introduction à Javascript ].match(/intro/i)=[Intro]
[ Introduction à Javascript ].replace('i','x')=[ Introductxon à Javascript ]
[ Introduction à Javascript ].replace(/i/g,'x')=[ Introductxon à Javascrxpt ]
[ Introduction à Javascript ].split(/\s*/)=[,I,n,t,r,o,d,u,c,t,i,o,n,à,J,a,v,a,s,c,r,i,p,t,]
[ Introduction à Javascript ].split(/\s+/)=[,Introduction,à,Javascript,]