Perché + è così male per la concatenazione?


44

Tutti continuano a dire che uno dei problemi di JavaScript sta usando +[ esempio ] per la concatenazione di stringhe. Alcuni sostengono che il problema non si sta utilizzando +, è la coercizione di tipo [vedere i commenti dell'esempio precedente]. Ma i linguaggi fortemente tipizzati usano + per la concatenazione e i tipi coerce senza alcun problema. Ad esempio, in C #:

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

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

Quindi perché la concatenazione di stringhe in JavaScript è un problema così grande?


17
perché è bad. Chi è Everyone?
Neal,

3
Penso che il problema sia + sia un operatore matematico. E che la funzione di concatinazione di + confonde quel processo standard. perché mentre "Hello" + il numero può funzionare il numero + "Hello" potrebbe non funzionare.
SoylentGray,

3
@Neal, sono d'accordo - Voglio sapere chi sembrano tutti questi mistici "tutti" in tutte queste domande.
GrandmasterB,

L'uso di + per la concatenazione è OK. L'uso della digitazione dinamica è OK. L'uso di entrambi nella stessa lingua è negativo ^ H ^ H ^ H porta all'ambiguità.
Gerry,

6
@Neal - "Everyone" sarebbe Douglas Crockford. Lo elenca come "orribile" nel suo libro, "JavaScript: le parti buone".
kirk.burleson,

Risposte:


68

Considera questo pezzo di codice JavaScript:

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

Questo accederà

il risultato è 1020

Quale molto probabilmente non è quello che era previsto e può essere un bug difficile da rintracciare.


4
Molto bella illustrazione del problema di fondo: la concatenazione di stringhe non è ben definita quando i tipi (stringa + int + int nell'esempio) vengono mescolati. Meglio avere un operatore completamente diverso (come "." Di Perl) con semantica ben definita.
Bruce Ediger,

9
O modo di risolvere questo Python, che sarebbe quello di costringere a avvolgere ae bin str(a)e str(b)chiamate; altrimenti, ottieni un ValueError: cannot concatenate 'str' and 'int'.
Aphex,

6
@FrustratedWithFormsDesigner: Aggiungi parentesi. 'result is ' + (a + b).
Jon Purdy,

18
Il fatto è che in C # potresti fare la stessa cosa e otterrai lo stesso risultato System.Console.WriteLine("result is " + 10 + 20);, ma nessuno si lamenta mai in C #. Questo è ciò che non capisco: cos'è JavaScript che lo rende più confuso?
configuratore

7
@configurator: perché alle persone viene detto che C # è perfetto e javascript è terribile. Sono entrambi sbagliati, ma la reputazione di una lingua sembra attenersi, le percezioni contano molto, soprattutto su Internet.
gbjbaanb,

43

Quando dici "cattivo" intendi "errato" o intendi "lento"? L'argomento sull'uso degli operatori matematici per eseguire la concatenazione di stringhe è probabilmente un argomento "errato", ma c'è anche un argomento da sostenere sul fatto che l'utilizzo +per eseguire molte concatenazioni di stringhe può essere molto lento.

Non stiamo parlando di "Hello" + numberquando parliamo di prestazioni, stiamo parlando di costruire una stringa relativamente grande aggiungendola ripetutamente in un ciclo.

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

In JavaScript (e C # del resto) le stringhe sono immutabili. Non possono mai essere modificati, sostituiti solo con altre stringhe. Probabilmente sei consapevole che combined + "hello "non modifica direttamente la combinedvariabile - l'operazione crea una nuova stringa che è il risultato della concatenazione delle due stringhe insieme, ma devi quindi assegnare quella nuova stringa alla combinedvariabile se vuoi che sia cambiata.

Quindi ciò che questo loop sta facendo è creare un milione di oggetti stringa diversi e buttarne via 999.999. Creare così tante stringhe che crescono continuamente di dimensioni non è veloce, e ora il garbage collector ha molto lavoro da fare per ripulire dopo questo.

C # presenta lo stesso identico problema, risolto in quell'ambiente dalla classe StringBuilder . In JavaScript, otterrai prestazioni molto migliori creando un array di tutte le stringhe che desideri concatenare e unendole poi una volta alla fine, anziché un milione di volte nel ciclo:

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

3
Questa è una risposta eccellente Non solo ha risposto alla domanda, ma è stato istruito.
Charles Sprayberry,

3
Questo non è ciò che intendevo affatto, è completamente estraneo alla domanda.
configuratore

4
Scusate. Sembra che almeno 7 persone abbiano frainteso la tua domanda dal modo in cui è stata formulata.
Joel Mueller,

9
Per quanto riguarda le prestazioni: forse è stato così nel 2011, ma ora il metodo + operator è molto più veloce rispetto al metodo array.join (almeno in v8). Guarda questo jsperf: jsperf.com/string-concatenation101
UpTheCreek

2
Hai idea di come il metodo join generi una stringa da più parti in un unico passaggio, invece di combinare poi una ad una, generando così anche tutte quelle stringhe intermedie?
Angelo.Hannes,

14

Non è male usare + sia per l'aggiunta che per la concatenazione, purché sia ​​possibile aggiungere solo numeri e concatenare solo stringhe. Tuttavia, Javascript si convertirà automaticamente tra numeri e stringhe secondo necessità, quindi avrai:

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

Forse più semplicemente, il sovraccarico di "+" in presenza della conversione automatica del tipo interrompe l'associatività prevista dell'operatore +:

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

2
Anche la proprietà commutativa dell'aggiunta manca dalla concatenazione 3 + 5 == 5 + 3ma"3" + "5" != "5" + "3"
Caleth,

10

Il problema tipico sollevato per la concatenazione di stringhe ruota attorno ad alcuni problemi:

  1. il +simbolo è sovraccarico
  2. semplici errori
  3. i programmatori sono pigri

1 #

Il primo e principale problema con l'utilizzo +di concatenazione e aggiunta di stringhe è l'utilizzo +di concatenazione e aggiunta di stringhe .

se hai variabili ae b, e hai impostato c = a + b, c'è un'ambiguità che dipende dai tipi di ae b. Questa ambiguità ti costringe a fare ulteriori passi per mitigare il problema:

String Concat:

c = '' + a + b;

aggiunta:

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

Questo mi porta al mio secondo punto

2 #

È molto semplice eseguire il cast accidentale di una variabile in una stringa senza accorgersene. È anche facile dimenticare che il tuo input sta arrivando come una stringa:

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

Produrrà risultati non intuitivi perché prompt restituisce il valore di stringa dell'input.

3 #

La necessità di digitare parseFloato Number()ogni volta che voglio fare un'aggiunta è noiosa e fastidiosa. Mi considero abbastanza intelligente da ricordare di non incasinare i miei tipi dinamici, ma ciò non significa che non abbia mai incasinato i miei tipi dinamici . La verità della questione è che sono troppo pigro per scrivere parseFloato Number()ogni volta che faccio l'aggiunta, perché faccio molta aggiunta.

Soluzione?

Non tutte le lingue utilizzano +per la concatenazione di stringhe. PHP utilizza .per concatenare le stringhe, il che aiuta a distinguere tra quando si desidera aggiungere numeri e quando si desidera unire le stringhe.

Qualsiasi simbolo può essere utilizzato per concatenare le stringhe, ma la maggior parte sono già utilizzate ed è meglio evitare la duplicazione. Se avessi la mia strada, probabilmente avrei usato _per unire le stringhe e non consentirei i _nomi delle variabili in.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.