As strings JavaScript são imutáveis?Preciso de um “construtor de strings” em JavaScript?

StackOverflow https://stackoverflow.com/questions/51185

  •  09-06-2019
  •  | 
  •  

Pergunta

O javascript usa strings imutáveis ​​ou mutáveis?Eu preciso de um "construtor de strings"?

Foi útil?

Solução

Eles são imutáveis.Você não pode alterar um caractere dentro de uma string com algo como var myString = "abbdef"; myString[2] = 'c'.Os métodos de manipulação de strings, como trim, slice retornar novas strings.

Da mesma forma, se você tiver duas referências à mesma string, modificar uma não afetará a outra

let a = b = "hello";
a = a + " world";
// b is not affected

No entanto, sempre ouvi o que Ash mencionou em sua resposta (que usar Array.join é mais rápido para concatenação), então queria testar os diferentes métodos de concatenação de strings e abstração da maneira mais rápida em um StringBuilder.Escrevi alguns testes para ver se isso é verdade (não é!).

Isso era o que eu acreditava que seria o caminho mais rápido, embora continuasse pensando que adicionar uma chamada de método poderia torná-lo mais lento...

function StringBuilder() {
    this._array = [];
    this._index = 0;
}

StringBuilder.prototype.append = function (str) {
    this._array[this._index] = str;
    this._index++;
}

StringBuilder.prototype.toString = function () {
    return this._array.join('');
}

Aqui estão os testes de velocidade de desempenho.Todos os três criam uma cadeia gigantesca composta de concatenações "Hello diggity dog" cem mil vezes em uma string vazia.

Eu criei três tipos de testes

  • Usando Array.push e Array.join
  • Usando indexação de array para evitar Array.push, então usando Array.join
  • Concatenação de string direta

Então criei os mesmos três testes abstraindo-os em StringBuilderConcat, StringBuilderArrayPush e StringBuilderArrayIndex http://jsperf.com/string-concat-without-sringbuilder/5 Por favor, vá lá e faça testes para que possamos obter uma boa amostra.Observe que corrigi um pequeno bug, então os dados dos testes foram apagados. Atualizarei a tabela assim que houver dados de desempenho suficientes.Vá para http://jsperf.com/string-concat-without-sringbuilder/5 para a tabela de dados antiga.

Aqui estão alguns números (última atualização em Ma5rch 2018), se você não quiser seguir o link.O número em cada teste está em 1.000 operações/segundo (mais alto é melhor)

| Browser          | Index | Push | Concat | SBIndex | SBPush | SBConcat |
---------------------------------------------------------------------------
| Chrome 71.0.3578 | 988   | 1006 | 2902   | 963     | 1008   | 2902     |
| Firefox 65       | 1979  | 1902 | 2197   | 1917    | 1873   | 1953     |
| Edge             | 593   | 373  | 952    | 361     | 415    | 444      |
| Exploder 11      | 655   | 532  | 761    | 537     | 567    | 387      |
| Opera 58.0.3135  | 1135  | 1200 | 4357   | 1137    | 1188   | 4294     | 

Descobertas

  • Hoje em dia, todos os navegadores perenes lidam bem com a concatenação de strings. Array.join só ajuda o IE 11

  • No geral, o Opera é mais rápido, 4 vezes mais rápido que o Array.join

  • Firefox é o segundo e Array.join é apenas um pouco mais lento no FF, mas consideravelmente mais lento (3x) no Chrome.

  • O Chrome é o terceiro, mas string concat é 3 vezes mais rápido que Array.join

  • A criação de um StringBuilder parece não afetar muito o desempenho.

Espero que alguém ache isso útil

Caso de teste diferente

Como o @RoyTinker achou que meu teste estava falho, criei um novo caso que não cria uma string grande concatenando a mesma string, ele usa um caractere diferente para cada iteração.A concatenação de strings ainda parecia mais rápida ou igualmente rápida.Vamos fazer esses testes funcionarem.

Sugiro que todos continuem pensando em outras maneiras de testar isso e sintam-se à vontade para adicionar novos links para diferentes casos de teste abaixo.

http://jsperf.com/string-concat-without-sringbuilder/7

Outras dicas

de livro rinoceronte:

No JavaScript, as cordas são objetos imutáveis, o que significa que os caracteres dentro deles podem não ser alterados e que quaisquer operações sobre strings realmente criam novas strings.As strings são atribuídas por referência, não por valor.Em geral, quando um objeto é atribuído por referência, uma alteração feita ao objeto por meio de uma referência será visível através de todas as outras referências ao objeto.Como as strings não podem ser alteradas, no entanto, você pode ter várias referências a um objeto String e não se preocupar com o fato de o valor da string mudar sem que você saiba

Dica de desempenho:

Se você tiver que concatenar strings grandes, coloque as partes da string em um array e use o comando Array.Join() método para obter a string geral.Isso pode ser muitas vezes mais rápido para concatenar um grande número de strings.

Não há StringBuilder em JavaScript.

Strings são imutáveis – eles não podem mudar, só podemos fazer novas cordas.

Exemplo:

var str= "Immutable value"; // it is immutable

var other= statement.slice(2, 10); // new string

O valor do tipo string é imutável, mas o objeto String, que é criado usando o construtor String(), é mutável, porque é um objeto e você pode adicionar novas propriedades a ele.

> var str = new String("test")
undefined
> str
[String: 'test']
> str.newProp = "some value"
'some value'
> str
{ [String: 'test'] newProp: 'some value' }

Entretanto, embora seja possível adicionar novas propriedades, não é possível alterar as propriedades já existentes

Captura de tela de um teste no console do Chrome

Em conclusão, 1.todo valor do tipo string (tipo primitivo) é imutável.2.O objeto String é mutável, mas o valor do tipo string (tipo primitivo) que ele contém é imutável.

Só para esclarecer mentes simples como a minha (de MDN):

Imutáveis ​​são os objetos cujo estado não pode ser alterado depois que o objeto é criado.

String e números são imutáveis.

Imutável significa que:

Você pode fazer com que o nome de uma variável aponte para um novo valor, mas o valor anterior ainda será mantido na memória.Daí a necessidade de coleta de lixo.

var immutableString = "Hello";

// No código acima, um novo objeto com valor string é criado.

immutableString = immutableString + "World";

// Agora estamos anexando "World" ao valor existente.

Parece que estamos modificando a string 'immutableString', mas não estamos.Em vez de:

Ao anexar "immutableString" com um valor de string, ocorrem os seguintes eventos:

  1. O valor existente de "immutableString" é recuperado
  2. "World" é anexado ao valor existente de "immutableString"
  3. O valor resultante é então alocado para um novo bloco de memória
  4. O objeto "immutableString" agora aponta para o espaço de memória recém-criado
  5. O espaço de memória criado anteriormente agora está disponível para coleta de lixo.

Em relação à sua pergunta (no seu comentário à resposta de Ash) sobre o StringBuilder no ASP.NET Ajax, os especialistas parecem discordar disso.

Christian Wenz diz em seu livro Programando ASP.NET AJAX (O'Reilly) que "esta abordagem não tem nenhum efeito mensurável na memória (na verdade, a implementação parece ser um pouco mais lenta do que a abordagem padrão)."

Por outro lado, Gallo et al dizem em seu livro ASP.NET AJAX em ação (Manning) que “Quando o número de strings a serem concatenadas é maior, o construtor de strings se torna um objeto essencial para evitar grandes quedas de desempenho”.

Acho que você precisaria fazer seu próprio benchmarking e os resultados também podem diferir entre os navegadores.No entanto, mesmo que não melhore o desempenho, ainda pode ser considerado "útil" para programadores acostumados a codificar com StringBuilders em linguagens como C# ou Java.

É uma postagem tardia, mas não encontrei uma boa citação de livro entre as respostas.

Aqui está uma exceção definitiva de um livro confiável:

Strings são imutáveis ​​em ECMAScript, o que significa que, uma vez criadas, seus valores não podem ser alterados.Para alterar a string contida em uma variável, a string original deve ser destruída e a variável preenchida com outra string contendo um novo valor... —JavaScript Profissional para Desenvolvedores Web, 3ª Ed., p.43

Agora, a resposta que cita o trecho do livro de rinoceronte está certo sobre a imutabilidade da corda, mas dizendo que "as sequências são atribuídas por referência, não por valor". (Provavelmente eles originalmente pretendiam colocar as palavras de uma maneira oposta).

O equívoco de "referência/valor" é esclarecido no "JavaScript Profissional", capítulo denominado "Valores primitivos e de referência":

Os cinco tipos primitivos...[são]:Indefinido, Nulo, Booleano, Número e String.Diz-se que essas variáveis ​​são acessadas por valor, porque você está manipulando o valor real armazenado na variável. —JavaScript Profissional para Desenvolvedores Web, 3ª Ed., p.85

isso se opõe a objetos:

Quando você manipula um objeto, você está realmente trabalhando em uma referência a esse objeto, e não no objeto em si.Por esse motivo, diz-se que tais valores são acessados ​​por referência.—JavaScript Profissional para Desenvolvedores Web, 3ª Ed., p.85

As strings JavaScript são realmente imutáveis.

Strings em Javascript são imutáveis

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top