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

6.1. script [str-01]
A primeira coisa a compreender é que, uma vez criada, uma cadeia de caracteres não pode ser modificada. Existem muitos métodos disponíveis para criar uma nova cadeia a partir da cadeia original, mas a cadeia original permanece inalterada. Além disso, uma cadeia de caracteres pode ser de dois tipos:
- [string] quando é inicializada com um literal de cadeia;
- [object] quando é criada como uma instância da classe [String];
'use strict';
// strings are read-only (cannot be modified)
// a chain
const chaîne1 = "abcd ";
// type
console.log("typeof(chaîne1)=", typeof (chaîne1));
// character n° 2
console.log("chaîne1[2]=", chaîne1[2]);
// causes an error
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 demonstra que uma string pode ser construída de duas maneiras.
'use strict';
// strings can be of two types
// a literal string
const chaîne1 = "abcd ";
// type
console.log("typeof(chaîne1)=", typeof (chaîne1));
// string instance
const chaîne2 = new String("xyzt");
// type
console.log("typeof(chaîne2)=", typeof (chaîne2));
// other entry (without new) - type [string] not [object]
const chaîne3 = String("12 34");
// type
console.log("typeof(chaîne3)=", typeof (chaîne3));
// type [string] and type [object] offer the same methods, those of the String class
console.log("chaîne1.length=", chaîne1.length);
console.log("chaîne2.length=", chaîne2.length);
Comentários
- linha 6: o método padrão para definir uma string. [string1] será do tipo [string];
- linha 10: uma string pode ser construída utilizando o construtor da classe [String]. [string2] 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] beneficia dos métodos da classe [String].
6.3. script [str-03]
Este script exibe uma string específica com interpolação de variáveis.
'use strict';
// chain
const chaîne = "Introduction à Javascript par l'exemple";
// chain with variable interpolation
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. Isto segue a mesma lógica das variáveis $ nas cadeias de caracteres do PHP. Repare na sintaxe para tal cadeia de caracteres: está entre crases (AltGr-7 num 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 ainda é insuficiente. Não é possível substituir a variável na expressão ${variable} por uma expressão. Para quem já programou em C, não há nada como as funções [printf, sprintf] para escrever ou construir strings formatadas. Centenas de programadores criaram milhares de pacotes JavaScript, formando um vasto ecossistema. Quando tem uma necessidade que não é satisfeita nativamente pelo JavaScript, é hora de procurar um pacote que a preencha. Para isso, usamos o gestor de pacotes [npm]. Ele tem uma opção de [pesquisa] que permite procurar uma string nas descrições dos pacotes. O [npm] retorna uma lista de pacotes que correspondem à pesquisa. Vamos, portanto, procurar a string [sprintf] nas descrições dos pacotes:

- na coluna [4], as palavras-chave dos pacotes na coluna [3];
- na coluna [5], as descrições dos pacotes da coluna [3];
O próximo passo é ir ao site do [npm], [https://www.npmjs.com/], e ler as descrições dos pacotes:

Em [3], analisamos a lista de pacotes e selecionamos um.

Na descrição do pacote, encontrará instruções para a sua instalação e utilização:

Instalamos o pacote [sprintf-js] num terminal [VSCode]:

Esta instalação irá modificar o ficheiro [package.json] localizado na raiz da pasta [javascript] [2]:

Como mostrado acima, o pacote foi instalado em [dependencies], ou seja, os pacotes necessários para executar o projeto. Lembre-se de que os pacotes necessários apenas durante o desenvolvimento do projeto são colocados em [devDependencies]. Estes não são utilizados durante a execução. Esta distinção é importante ao criar a versão final do projeto para implementação em produção. Existem ferramentas disponíveis para:
- combinar todos os ficheiros JavaScript necessários para a execução num único ficheiro. Os pacotes em [devDependencies] não são, portanto, incluídos neste ficheiro final;
- minimizá-lo, ou seja, reduzir o seu tamanho tanto quanto possível. Para tal, por exemplo, todos os comentários são removidos;
- “ofuscar” o código para torná-lo difícil de compreender. Por exemplo, as variáveis rate, salary e tax serão substituídas pelas variáveis a, b e c;
- Realizar outras otimizações;
Esta otimização do ficheiro final de um projeto JavaScript é utilizada na programação web. Uma aplicação web pode depender de um grande número de ficheiros JavaScript. Carregar estes ficheiros num navegador pode tornar mais lenta a exibição da primeira página da aplicação. A otimização descrita acima visa melhorar este tempo de carregamento. Se os utilizadores considerarem o tempo de carregamento demasiado longo, a aplicação não será utilizada.
Agora que temos o pacote [sprintf-js], precisamos de o utilizar. Este é o script [str-04]:
'use strict';
// use of an external package to provide the sprintf function
import { sprintf } from 'sprintf-js';
// chain
const chaîne = "Introduction à Javascript par l'exemple";
// method
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 descobrir o que o pacote exporta, pode consultar o seu código:

- em [1], clique com o botão direito do rato no pacote importado;
- em [2], queremos ver a sua definição;
- em [3-4], vemos que o pacote exporta uma função chamada [sprintf];
A função [sprintf] do pacote [sprintf-js] é importada utilizando a seguinte instrução:
import { sprintf } from 'sprintf-js';
O código completo:
'use strict';
// use of an external package to provide the sprintf function
import { sprintf } from 'sprintf-js';
// chain
const chaîne = "Introduction à Javascript par l'exemple";
// method
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)
Linha 3: A instrução [import] não é reconhecida. Isto deve-se ao facto de a versão 10.15.1 do [node.js] utilizada neste curso (setembro de 2019) ainda não suportar o padrão ECMAScript para a importação de pacotes denominados módulos. Em 2019, o [node.js] suporta um padrão de módulos chamado CommonJS. A integração dos módulos ECMAScript pelo [node.js] está prevista para 2020. Mais uma vez, os programadores deram um passo em frente e criaram pacotes que permitem a utilização de módulos ES6 com o [node.js] já neste momento (2019).
Iremos utilizar um pacote chamado [esm] (ECMAScript Modules). Instalamo-lo num terminal para o projeto [javascript]:

Em [4], podemos ver que a instalação do pacote [esm] [1-3] modificou o ficheiro [javascript/package.json].
Ainda não terminámos. Para que o módulo [esm] seja utilizado pelo [node.js], precisamos de o executar com o argumento [-r esm].
Por isso, modificamos a configuração da extensão [Code Runner] no [VSCode]:


Em [11], adicionamos o argumento [-r esm] e guardamos (Ctrl-S) a configuração.
Agora podemos executar o script [str-04]:
'use strict';
// use of an external package to provide the sprintf function
import { sprintf } from 'sprintf-js';
// chain
const chaîne = "Introduction à Javascript par l'exemple";
// substr method
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));

6.5. script [str-05]
Eis o que a documentação diz sobre a função [sprintf]:
Os marcadores de posição na cadeia de formato são indicados por % e seguidos por um ou mais destes elementos, nesta ordem:
- Um número opcional seguido do sinal $ que seleciona qual índice de argumento usar para o valor. Se não for especificado, os argumentos serão colocados na mesma ordem que os marcadores de posição na cadeia de caracteres de entrada.
- Um sinal + opcional que força o resultado a ser precedido por um sinal de mais ou de menos para valores numéricos. Por predefinição, apenas o sinal - é utilizado para números negativos.
- Um especificador de preenchimento opcional que indica qual o carácter a utilizar para o preenchimento (se especificado). Os valores possíveis são 0 ou qualquer outro carácter precedido por uma ' (aspas simples). O padrão é preencher com espaços.
- Um sinal - opcional que faz com que o sprintf alinhe à esquerda o resultado deste espaço reservado. O padrão é alinhar o resultado à direita.
- Um número opcional que especifica o número de caracteres que o resultado deve conter. Se o valor a ser devolvido for mais curto do que este número, o resultado será preenchido. Quando utilizado com o especificador de tipo j (JSON), o comprimento de preenchimento especifica o tamanho da tabulação utilizada para a indentação.
- Um modificador de precisão opcional, composto por um . (ponto) seguido de um número, que especifica quantos dígitos devem ser exibidos para números de ponto flutuante. Quando utilizado com o especificador de tipo g, especifica o número de dígitos significativos. Quando utilizado numa cadeia de caracteres, faz com que o resultado seja truncado.
- Um especificador de tipo que pode ser qualquer um dos seguintes:
- % — produz um caractere % literal
- b — retorna um número inteiro na forma binária
- c — retorna um inteiro como o caractere com esse valor ASCII
- d ou i — retorna um inteiro como um número decimal com sinal
- e — retorna um número de precisão flutuante usando notação científica
- u — retorna um inteiro como um número decimal sem sinal
- f — devolve um número de precisão flutuante tal como está; ver notas sobre precisão acima
- g — devolve um número de precisão flutuante tal como está; ver notas sobre precisão acima
- o — retorna um inteiro como um número octal
- s — devolve uma cadeia de caracteres tal como está
- t — retorna verdadeiro ou falso
- T — devolve o tipo do argumento1
- v — devolve o valor primitivo do argumento especificado
- x — retorna um inteiro como um número hexadecimal (minúsculas)
- X — retorna um inteiro como um número hexadecimal (em maiúsculas)
- j — retorna um objeto ou matriz JavaScript como uma string codificada em JSON
O script [script-05] implementa alguns destes formatos:
'use strict';
// use of an external package to provide the sprintf function
import { sprintf } from 'sprintf-js';
// chain
const chaîne = "Javascript";
// character strings
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));
// integers
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));
// real
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 }));
// type
console.log(sprintf("type personne (%%T)=%T", { nom: "mathieu", âge: 34 }));
// boolean
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] demonstra alguns métodos da classe [String] que também podem ser utilizados no tipo [string]:
'use strict';
// use of an external package to provide the sprintf function
import { sprintf } from 'sprintf-js';
// chain
const chaîne = " Introduction à Javascript ";
// a few methods
// substr(10,2): 2 characters starting from number 10
console.log(sprintf("[%s].substr(10,2)=[%s]", chaîne, chaîne.substr(10, 2)));
// trim: eliminates blanks at the beginning and end of a chain (blank=b \t \r \n \f)
console.log(sprintf("[%s].trim()=[%s]", chaîne, chaîne.trim()));
// toLowerCase: transformation to lower case
console.log(sprintf("[%s].toLowerCase=[%s]", chaîne, chaîne.toLowerCase()));
// toUpperCase: transformation into uppercase letters
console.log(sprintf("[%s].toUpperCase=[%s]", chaîne, chaîne.toUpperCase()));
// indexOf: position of a searched string within the string, -1 if the substring doesn't exist
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: true if the string searched for is in the string
console.log(sprintf("[%s].includes('Java')=[%s]", chaîne, chaîne.includes('Java')));
// length: string length - not a method but a property
console.log(sprintf("[%s].length=[%s]", chaîne, chaîne.length));
// slice (7,10): strings of characters 7 to 9
console.log(sprintf("[%s].slice(7,10)=[%s]", chaîne, chaîne.slice(7, 10)));
// match: searches for an expression in the string - this expression can be a regular expression
// /intro/i: regular expression designating the string [intro] in upper or lower case
// returns the string found
console.log(sprintf("[%s].match(/intro/i)=[%s]", chaîne, chaîne.match(/intro/i)));
// replace: replaces string1 with string2 in string
// replaces the 1st occurrence of i with x
console.log(sprintf("[%s].replace('i','x')=[%s]", chaîne, chaîne.replace('i', 'x')));
// replaces all occurrences of i with x
// /i/g is a regular expression designating all (g) occurrences of i
console.log(sprintf("[%s].replace(/i/g,'x')=[%s]", chaîne, chaîne.replace(/i/g, 'x')));
// split: splits the string into words separated by the split parameter
// renders the table of these words
// /\s*/ : words separated by 0 or more spaces
console.log(sprintf("[%s].split(/\\s*/)=[%s]", chaîne, chaîne.split(/\s*/)));
// /\s+/ : words separated by one or more spaces
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,]