Por que + é tão ruim para concatenação?


44

Todo mundo fica dizendo que um dos problemas do JavaScript está usando +[ exemplo ] para concatenação de strings. Alguns dizem que o problema não está sendo usado +, é tipo coerção [veja os comentários do exemplo anterior]. Mas linguagens fortemente tipadas usam + para concatenação e coerção de tipos sem nenhum problema. Por exemplo, em C #:

int number = 1;
MyObject obj = new MyObject();

var result = "Hello" + number + obj;
// is equivalent to
string result = "hello" + number.ToString() + obj.ToString();

Então, por que a concatenação de strings no JavaScript é um problema tão grande?


17
por que é bad. Quem é Everyone?
Neal

3
Eu acho que o problema é + é um operador matemático. E que a função de concatinação do + confunde esse processo padrão. porque enquanto "Hello" + número pode funcionar número + "Hello" pode não funcionar.
SoylentGray

3
@ Neal, eu concordo - eu quero saber quem todos esses místicos 'todo mundo' parecem estar em todas essas perguntas.
GrandmasterB

Usar + para concatenação está OK. O uso da digitação dinâmica está OK. Usar os dois no mesmo idioma é ruim ^ H ^ H ^ H leva à ambiguidade.
Gerry

6
@ Neal - "Todo mundo" seria Douglas Crockford. Ele a lista como "horrível" em seu livro "JavaScript: The Good Parts".
Kirk.burleson

Respostas:


68

Considere esta parte do código JavaScript:

var a = 10;
var b = 20;
console.log('result is ' + a + b);

Isso registrará

resultado é 1020

O que provavelmente não é o que foi planejado e pode ser um bug difícil de rastrear.


4
Ilustração muito boa do problema subjacente: a concatenação de strings não está bem definida quando tipos (string + int + int no exemplo) são misturados. Melhor ter um operador totalmente diferente (como o '.' De Perl) com semântica bem definida.
9788 Bruce Ediger

9
Ou maneira de resolver este Python, que seria forçá-lo a embrulhar ae bem str(a)e str(b)chamadas; caso contrário, você recebe um ValueError: cannot concatenate 'str' and 'int'.
Aphex

6
@FrustratedWithFormsDesigner: adicione parênteses. 'result is ' + (a + b).
9119 Jon Purdy

18
O problema é que, em C #, você poderia fazer a mesma coisa e obterá o mesmo resultado - System.Console.WriteLine("result is " + 10 + 20);, mas nunca ninguém se queixa disso em C #. É isso que eu não entendo - o que é o JavaScript que o torna mais confuso?
Configurator

7
@ configurador: porque as pessoas dizem que o C # é perfeito e o javascript é péssimo. Ambos estão errados, mas a reputação de um idioma parece manter-se, as percepções contam muito, especialmente nas internets.
Gbjbaanb

43

Quando você diz "ruim", significa "incorreto" ou "lento"? O argumento sobre o uso de operadores matemáticos para concatenação de strings é sem dúvida um argumento "incorreto", mas também há um argumento a ser feito que o uso +para fazer muita concatenação de strings pode ser muito lento.

Não estamos falando sobre "Hello" + numberquando falamos sobre desempenho, mas sobre como construir uma cadeia relativamente grande anexando-a repetidamente em um loop.

var combined = "";
for (var i = 0; i < 1000000; i++) {
    combined = combined + "hello ";
}

Em JavaScript (e C #), as strings são imutáveis. Eles nunca podem ser alterados, apenas substituídos por outras strings. Você provavelmente está ciente de que combined + "hello "não modifica diretamente a combinedvariável - a operação cria uma nova sequência resultante da concatenação das duas seqüências juntas, mas você deve atribuir essa nova sequência à combinedvariável, se desejar que ela seja alterada.

Então, o que esse loop está fazendo é criar um milhão de objetos de string diferentes e jogar fora 999.999 deles. Criar muitas seqüências de caracteres que crescem continuamente em tamanho não é rápido, e agora o coletor de lixo tem muito trabalho a fazer para limpar depois disso.

O C # tem exatamente o mesmo problema, resolvido nesse ambiente pela classe StringBuilder . Em JavaScript, você obtém um desempenho muito melhor criando uma matriz de todas as sequências que deseja concatenar e juntando-as uma vez no final, em vez de um milhão de vezes no ciclo:

var parts = [];
for (var i = 0; i < 1000000; i++) {
    parts.push("hello");
}
var combined = parts.join(" ");

3
Esta é uma excelente resposta. Não apenas respondeu à pergunta, mas também educou.
Charles Sprayberry

3
Isso não é o que eu quis dizer, porém, não tem nenhuma relação com a questão.
Configurator

4
Desculpa. Parece que pelo menos 7 pessoas entenderam sua pergunta da maneira como foi redigida.
Joel Mueller

9
Re-desempenho: Talvez esse tenha sido o caso em 2011, mas agora o método do operador + é muito mais rápido que o método array.join (pelo menos na v8). Veja isto jsperf: jsperf.com/string-concatenation101
UpTheCreek

2
Alguma idéia de como o método join gera uma string de várias partes em uma etapa, em vez de também combinar uma por uma, gerando também todas essas strings intermediárias?
Angelo.Hannes

14

Não é ruim usar + para adição e concatenação, desde que você possa adicionar apenas números e concatenar seqüências de caracteres. No entanto, o Javascript converterá automaticamente entre números e seqüências de caracteres conforme necessário, para que você tenha:

3 * 5 => 15
"3" * "5" => 15
2 + " fish" => "2 fish"
"3" + "5" => "35"  // hmmm...

Talvez, mais simplesmente, sobrecarregar "+" na presença de conversão automática de tipo interrompa a associatividade esperada do operador +:

("x" + 1) + 3 != "x" + (1 + 3)

2
Também a propriedade comutativa da adição está faltando concatenação 3 + 5 == 5 + 3mas"3" + "5" != "5" + "3"
Caleth

10

O problema típico levantado para a concatenação de cadeias de caracteres gira em torno de alguns problemas:

  1. o +símbolo está sendo sobrecarregado
  2. erros simples
  3. programadores sendo preguiçosos

# 1

O primeiro e mais importante problema com o uso +para concatenação e adição de strings é que você está usando +para concatenação e adição de strings .

se você tiver variáveis ae b, e definir c = a + b, há uma ambiguidade dependente dos tipos de ae b. Essa ambiguidade força você a tomar medidas extras para atenuar o problema:

Concat de String:

c = '' + a + b;

Adição:

c = parseFloat(a) + parseFloat(b);

Isso me leva ao meu segundo ponto

# 2

É muito fácil converter acidentalmente uma variável em uma string sem perceber. Também é fácil esquecer que sua entrada está chegando como uma string:

a = prompt('Pick a number');
b = prompt('Pick a second number');
alert( a + b );

Produzirá resultados não intuitivos porque prompt retorna o valor da string da entrada.

# 3

Precisando digitar parseFloatou Number()toda vez que eu quero fazer adição é tedioso e irritante. Eu me considero inteligente o suficiente para lembrar de não estragar meus tipos dinâmicos, mas isso não significa que nunca estraguei meus tipos dinâmicos . A verdade é que tenho preguiça de digitar parseFloatou Number()toda vez que faço acréscimo, porque faço muito acréscimo.

Solução?

Nem todos os idiomas usam +para concatenação de cadeias. O PHP usa .para concatenar cadeias de caracteres, o que ajuda a distinguir entre quando você deseja adicionar números e quando deseja associar cadeias.

Qualquer símbolo pode ser usado para concatenar seqüências de caracteres, mas a maioria já está sendo usada, e é melhor evitar a duplicação. Se eu tivesse o que queria, provavelmente usaria _para juntar seqüências de caracteres e proibir os _nomes de variáveis.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.