Les chaînes JavaScript sont-elles immuables ?Ai-je besoin d’un « générateur de chaînes » en JavaScript ?

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

  •  09-06-2019
  •  | 
  •  

Question

Javascript utilise-t-il des chaînes immuables ou mutables ?Ai-je besoin d’un « constructeur de chaînes » ?

Était-ce utile?

La solution

Ils sont immuables.Vous ne pouvez pas modifier un caractère dans une chaîne avec quelque chose comme var myString = "abbdef"; myString[2] = 'c'.Les méthodes de manipulation de chaînes telles que trim, slice renvoie de nouvelles chaînes.

De la même manière, si vous avez deux références à la même chaîne, modifier l'une n'affecte pas l'autre.

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

Cependant, j'ai toujours entendu ce qu'Ash a mentionné dans sa réponse (à savoir que l'utilisation de Array.join est plus rapide pour la concaténation), j'ai donc voulu tester les différentes méthodes de concaténation de chaînes et d'abstraction de la manière la plus rapide dans un StringBuilder.J'ai écrit quelques tests pour voir si cela est vrai (ce n'est pas le cas !).

C'était ce que je pensais être le moyen le plus rapide, même si je pensais que l'ajout d'un appel de méthode pourrait le ralentir...

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('');
}

Voici des tests de vitesse de performances.Tous les trois créent une gigantesque chaîne composée de concaténation "Hello diggity dog" cent mille fois dans une chaîne vide.

J'ai créé trois types de tests

  • En utilisant Array.push et Array.join
  • Utiliser l'indexation de tableaux pour éviter Array.push, puis en utilisant Array.join
  • Concaténation de chaînes droites

Ensuite, j'ai créé les trois mêmes tests en les résumant dans StringBuilderConcat, StringBuilderArrayPush et StringBuilderArrayIndex http://jsperf.com/string-concat-without-sringbuilder/5 S'il vous plaît, allez-y et effectuez des tests afin que nous puissions obtenir un bon échantillon.Notez que j'ai corrigé un petit bug, donc les données des tests ont été effacées, je mettrai à jour le tableau une fois qu'il y aura suffisamment de données de performances.Aller à http://jsperf.com/string-concat-without-sringbuilder/5 pour l'ancienne table de données.

Voici quelques chiffres (Dernière mise à jour dans Ma5rch 2018), si vous ne souhaitez pas suivre le lien.Le nombre sur chaque test est en 1000 opérations/seconde (plus haut c'est mieux)

| 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     | 

Résultats

  • De nos jours, tous les navigateurs persistants gèrent bien la concaténation de chaînes. Array.join n'aide que IE 11

  • Dans l'ensemble, Opera est le plus rapide, 4 fois plus rapide qu'Array.join

  • Firefox est deuxième et Array.join n'est que légèrement plus lent dans FF mais considérablement plus lent (3x) dans Chrome.

  • Chrome est troisième mais la concaténation de chaînes est 3 fois plus rapide que Array.join

  • La création d'un StringBuilder ne semble pas trop affecter les performances.

J'espère que quelqu'un d'autre trouvera cela utile

Cas de test différent

Puisque @RoyTinker pensait que mon test était défectueux, j'ai créé un nouveau cas qui ne crée pas une grosse chaîne en concaténant la même chaîne, il utilise un caractère différent pour chaque itération.La concaténation des chaînes semblait toujours plus rapide, voire tout aussi rapide.Lançons ces tests.

Je suggère à tout le monde de continuer à réfléchir à d'autres façons de tester cela, et n'hésitez pas à ajouter de nouveaux liens vers différents cas de test ci-dessous.

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

Autres conseils

du livre de rhinocéros:

En JavaScript, les chaînes sont des objets immuables, ce qui signifie que les caractères qui ne peuvent pas être modifiés et que toutes les opérations sur des chaînes créent réellement de nouvelles chaînes.Les chaînes sont attribuées par référence, et non par valeur.En général, lorsqu'un objet est attribué par référence, une modification apportée à l'objet via une référence sera visible à travers toutes les autres références à l'objet.Parce que les chaînes ne peuvent pas être modifiées, cependant, vous pouvez avoir plusieurs références à un objet String et ne pas vous soucier que la valeur de la chaîne change sans que vous le sachiez

Conseil de performances :

Si vous devez concaténer de grandes chaînes, placez les parties de chaîne dans un tableau et utilisez le Array.Join() méthode pour obtenir la chaîne globale.Cela peut être plusieurs fois plus rapide pour concaténer un grand nombre de chaînes.

Il n'y a pas StringBuilder en JavaScript.

Les chaînes sont immuables – ils ne peuvent pas changer, nous ne pouvons que créer de nouvelles cordes.

Exemple:

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

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

La valeur du type chaîne est immuable, mais l'objet String, créé à l'aide du constructeur String(), est mutable, car il s'agit d'un objet et vous pouvez lui ajouter de nouvelles propriétés.

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

En attendant, même si vous pouvez ajouter de nouvelles propriétés, vous ne pouvez pas modifier les propriétés déjà existantes.

Une capture d'écran d'un test dans la console Chrome

En conclusion, 1.toute valeur de type chaîne (type primitif) est immuable.2.L'objet String est mutable, mais la valeur de type chaîne (type primitif) qu'il contient est immuable.

Juste pour clarifier pour les esprits simples comme le mien (de MDN):

Les immuables sont les objets dont l'état ne peut pas être modifié une fois l'objet créé.

La chaîne et les nombres sont immuables.

Immuable signifie que :

Vous pouvez faire pointer un nom de variable vers une nouvelle valeur, mais la valeur précédente est toujours conservée en mémoire.D’où la nécessité d’une collecte des déchets.

var immutableString = "Hello";

// Dans le code ci-dessus, un nouvel objet avec une valeur de chaîne est créé.

immutableString = immutableString + "World";

// Nous ajoutons maintenant "World" à la valeur existante.

On dirait que nous sommes en train de muter la chaîne « immutableString », mais ce n'est pas le cas.Plutôt:

Lors de l'ajout de "immutableString" avec une valeur de chaîne, les événements suivants se produisent :

  1. La valeur existante de "immutableString" est récupérée
  2. "World" est ajouté à la valeur existante de "immutableString"
  3. La valeur résultante est ensuite allouée à un nouveau bloc de mémoire
  4. L'objet "immutableString" pointe désormais vers l'espace mémoire nouvellement créé
  5. L'espace mémoire précédemment créé est désormais disponible pour le garbage collection.

Concernant votre question (dans votre commentaire sur la réponse d'Ash) sur StringBuilder dans ASP.NET Ajax, les experts semblent être en désaccord sur celle-ci.

Christian Wenz dit dans son livre Programmation ASP.NET AJAX (O'Reilly) que "cette approche n'a aucun effet mesurable sur la mémoire (en fait, la mise en œuvre semble être un peu plus lente que l'approche standard)."

D'un autre côté, Gallo et al disent dans leur livre ASP.NET AJAX en action (Manning) que "Lorsque le nombre de chaînes à concaténer est plus grand, le générateur de chaînes devient un objet essentiel pour éviter d'énormes baisses de performances."

Je suppose que vous devrez effectuer votre propre analyse comparative et les résultats peuvent également différer d'un navigateur à l'autre.Cependant, même si cela n'améliore pas les performances, il peut toujours être considéré comme "utile" pour les programmeurs habitués à coder avec StringBuilders dans des langages comme C# ou Java.

C'est un article tardif, mais je n'ai pas trouvé de bonne citation de livre parmi les réponses.

Voici un extrait définitif d'un livre fiable :

Les chaînes sont immuables dans ECMAScript, ce qui signifie qu'une fois créées, leurs valeurs ne peuvent pas changer.Pour changer la chaîne détenue par une variable, la chaîne d'origine doit être détruite et la variable remplie avec une autre chaîne contenant une nouvelle valeur... —JavaScript professionnel pour les développeurs Web, 3e éd., p.43

Maintenant, la réponse qui cite l'extrait de Rhino Book est juste sur l'immuabilité des cordes, mais une mauvaise division "Les chaînes sont attribuées par référence, et non par valeur." (Probablement ils voulaient à l'origine mettre les mots de manière opposée).

L'idée fausse « référence/valeur » est clarifiée dans le chapitre « JavaScript professionnel », intitulé « Valeurs primitives et de référence » :

Les cinq types primitifs...[sont] :Indéfini, Null, Booléen, Nombre et Chaîne.On dit que ces variables sont accessibles par valeur, car vous manipulez la valeur réelle stockée dans la variable. —JavaScript professionnel pour les développeurs Web, 3e éd., p.85

c'est opposé à objets:

Lorsque vous manipulez un objet, vous travaillez en réalité sur une référence à cet objet plutôt que sur l'objet lui-même.Pour cette raison, ces valeurs sont dites accessibles par référence.—JavaScript professionnel pour les développeurs Web, 3e éd., p.85

Les chaînes JavaScript sont en effet immuables.

Les chaînes en Javascript sont immuables

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top