Fermer

juillet 22, 2019

Le guide essentiel de la nouvelle version de JavaScript: BigInt


En JavaScript, le type Number ne peut représenter en toute sécurité des valeurs entières supérieures à 2⁵³. Cette limitation a obligé les développeurs à utiliser des solutions de contournement inefficaces et des bibliothèques tierces. BigInt est un nouveau type de données destiné à résoudre ce problème.

Le type de données BigInt vise à permettre aux programmeurs JavaScript de représenter des valeurs entières supérieures à la plage prise en charge par le type de données Number . La possibilité de représenter des entiers avec une précision arbitraire est particulièrement importante lors de l'exécution d'opérations mathématiques sur de grands entiers. Avec BigInt le dépassement d'entier ne constitue plus un problème.

De plus, vous pouvez travailler en toute sécurité avec des horodatages à haute résolution, des identificateurs d'entiers de grande taille, etc. sans avoir recours à une solution de contournement. BigInt est actuellement une proposition de stade 3. Une fois ajouté à la spécification, il deviendra le deuxième type de données numérique en JavaScript, ce qui portera le nombre total de types de données pris en charge à huit:

  • Boolean
  • Null
  • Undefined
  • Number
  • BigInt
  • String
  • Symbole
  • Object

Dans cet article, nous allons examiner de près BigInt et voir comment il peut aider à surmonter les limitations du Number . ] tapez JavaScript.

Le problème

L'absence d'un type entier explicite en JavaScript est souvent déconcertante pour les programmeurs venant d'autres langages. De nombreux langages de programmation prennent en charge plusieurs types numériques tels que float, double, integer et bignum, mais ce n'est pas le cas avec JavaScript. En JavaScript, tous les nombres sont représentés au format à virgule flottante double précision à 64 bits tel que défini par la norme IEEE 754-2008 .

Selon cette norme, très grands entiers qui ne peuvent pas être exactement représentés sont automatiquement arrondis. Pour être précis, le type Number en JavaScript ne peut représenter en toute sécurité que des entiers compris entre -9007199254740991 (- (2 53 -1)) et 9007199254740991 (2 53 1). Toute valeur entière qui se situe en dehors de cette plage peut perdre en précision.

Ceci peut être facilement examiné en exécutant le code suivant:

 console.log (9999999999999999); // → 10000000000000000

Cet entier est supérieur au plus grand nombre que JavaScript peut représenter de manière fiable avec la primitive Number . Par conséquent, il est arrondi. Un arrondi inattendu peut compromettre la fiabilité et la sécurité d’un programme. Voici un autre exemple:

 // remarquez les derniers chiffres
9007199254740992 === 9007199254740993; // → true

JavaScript fournit la constante Number.MAX_SAFE_INTEGER qui vous permet d'obtenir rapidement le nombre entier sécurisé maximal en JavaScript. De même, vous pouvez obtenir le nombre entier sécurisé minimal à l'aide de la constante Number.MIN_SAFE_INTEGER :

 const minInt = Number.MIN_SAFE_INTEGER;

console.log (minInt); // → -9007199254740991

console.log (minInt - 5); // → -9007199254740996

// remarque comment cela produit la même valeur que ci-dessus
console.log (minInt - 4); // → -9007199254740996

La solution

Pour contourner ce problème, certains développeurs JavaScript représentent de grands entiers utilisant le type String . L'API Twitter par exemple, ajoute une version sous forme de chaîne d'ID à des objets lors d'une réponse avec JSON. En outre, un certain nombre de bibliothèques telles que bignumber.js ont été développées pour faciliter l'utilisation des grands entiers.

Avec BigInt les applications n'ont plus besoin de solution de contournement ni de bibliothèque pour se protéger. représente des nombres entiers au-delà de Number.MAX_SAFE_INTEGER et Number.Min_SAFE_INTEGER . Les opérations arithmétiques sur des entiers de grande taille peuvent désormais être effectuées en JavaScript standard sans risquer de perte de précision. L'avantage supplémentaire d'utiliser un type de données natif sur une bibliothèque tierce est une meilleure performance au moment de l'exécution.

Pour créer un BigInt ajoutez simplement n à la fin d'un entier. Comparez:

 console.log (9007199254740995n); // → 9007199254740995n
console.log (9007199254740995); // → 9007199254740996

Vous pouvez également appeler le constructeur BigInt () :

 BigInt ("9007199254740995"); // → 9007199254740995n

Les littéraux BigInt peuvent également être écrits en notation binaire, octale ou hexadécimale:


 // binaire
console.log (0b1000000000000000000000000000000000000000000000000000000011n);
// → 9007199254740995n

// hex
console.log (0x20000000000003n);
// → 9007199254740995n

// octal
console.log (0o400000000000000003n);
// → 9007199254740995n

// remarque que la syntaxe octale héritée n'est pas prise en charge
console.log (0400000000000000003n);
// → SyntaxError

N'oubliez pas que vous ne pouvez pas utiliser l'opérateur d'égalité stricte pour comparer un BigInt à un nombre régulier car ils ne sont pas du même type:

 console.log (10n === dix); // → faux

console.log (type de 10n); // → bigint
console.log (type de 10); // → nombre

Vous pouvez utiliser l'opérateur d'égalité, qui effectue une conversion de type implicite avant de compiler ses opérandes:

 console.log (10n == 10); // → true

Tous les opérateurs arithmétiques peuvent être utilisés sur les BigInt sauf les opérateurs unaires plus ( + ):

 10n + 20n; // → 30n
10n - 20n; // → -10n
+ 10n; // → TypeError: Impossible de convertir une valeur BigInt en nombre
-10n; // → -10n
10n * 20n; // → 200n
20n / 10n; // → 2n
23n% 10n; // → 3n
10n ** 3n; // → 1000n

const x = 10n;
++ x; // → 11n
--X; // → 9n

La raison pour laquelle l'opérateur unaire plus ( + ) n'est pas pris en charge est que certains programmes peuvent s'appuyer sur l'invariant selon lequel + produit toujours un numéro ou lève une exception. Changer le comportement de + aurait également pour effet de casser le code.

Naturellement, lorsqu'il est utilisé avec les opérandes BigInt les opérateurs arithmétiques sont supposés renvoyer un BigInt . valeur. Par conséquent, le résultat de l'opérateur de division ( / ) est automatiquement arrondi au nombre entier inférieur le plus proche. Par exemple:

 25/10; // → 2.5
25n / 10n; // → 2n

Conversion de type implicite

Etant donné que la conversion de type implicite peut perdre des informations, les opérations mixtes entre BigInt et Nombre ne sont pas autorisées. Lors du mélange de grands nombres entiers et de nombres à virgule flottante, la valeur résultante peut ne pas être représentée avec précision par BigInt ou Number . Prenons l'exemple suivant:

 (9007199254740992n + 1n) + 0.5

Le résultat de cette expression est en dehors du domaine des deux BigInt et du Number . A Le numéro avec une partie décimale ne peut pas être converti avec précision en un BigInt . Et un BigInt supérieur à 2 53 ne peut pas être converti avec précision en un numéro .

En raison de cette restriction, il est impossible d'effectuer des opérations arithmétiques. avec un mélange d'opérandes Number et BigInt . Vous ne pouvez pas non plus transmettre un BigInt aux API Web et aux fonctions JavaScript intégrées qui attendent un numéro . Si vous tentez de le faire, un TypeError :

 10 + 10n; // → TypeError
Math.max (2n, 4n, 6n); // → TypeError

Notez que les opérateurs relationnels ne suivent pas cette règle, comme le montre cet exemple:

 10n> 5; // → true

Si vous souhaitez effectuer des calculs arithmétiques avec BigInt et Number vous devez d'abord déterminer le domaine dans lequel l'opération doit être effectuée. Pour cela, convertissez simplement l'un des opérandes en appelant Number () ou BigInt () :

 BigInt (10) + 10n; // → 20n
// ou
10 + nombre (10n); // → 20

Lorsqu'il est rencontré dans un contexte booléen BigInt est traité de la même manière que Number . En d'autres termes, un BigInt est considéré comme une valeur de vérité tant qu'il n'est pas 0n :

 si (5n) {
    // ce bloc de code sera exécuté
}

si (0n) {
    // mais ce bloc de code ne le fera pas
}

Aucune conversion implicite de type n'a lieu lors du tri d'un tableau de BigInt s et de Number s:

 const arr = [3n, 4, 2, 1n, 0, -1n];

arr.sort (); // → [-1n, 0, 1n, 2, 3n, 4]

Exploitants binaires tels que | & << >> et ^ fonctionnent sur BigInt de manière similaire à Number s. Les nombres négatifs sont interprétés comme un complément de longueur infinie deux. Les opérandes mixtes ne sont pas autorisés. Voici quelques exemples:

 90 | 115; // → 123
90n | 115n; // → 123n
90n | 115; // → TypeError

Le constructeur BigInt

Comme pour les autres types primitifs, un BigInt peut être créé à l'aide d'une fonction constructeur. L'argument passé à BigInt () est automatiquement converti en un BigInt si possible:

 BigInt ("10"); // → 10n
BigInt (10); // → 10n
BigInt (true); // → 1n

Les types de données et les valeurs qui ne peuvent pas être converties jettent une exception:

 BigInt (10.2); // → RangeError
BigInt (null); // → TypeError
BigInt ("abc"); // → SyntaxError

Vous pouvez effectuer directement des opérations arithmétiques sur un BigInt créé à l'aide d'un constructeur:

 BigInt (10) * 10n; // → 100n

Lorsqu'ils sont utilisés en tant qu'opérandes de l'opérateur d'égalité stricte, les BigInt créés à l'aide d'un constructeur sont traités comme des opérateurs normaux:

 BigInt (true) === 1n; // → true

Fonctions de bibliothèque

JavaScript fournit deux fonctions de bibliothèque pour représenter les valeurs BigInt sous forme d'entiers signés ou non signés:

  • BigInt.asUintN (width, BigInt) : enveloppe un BigInt entre 0 et 2 width -1
  • BigInt.asInt (largeur, BigInt) : enveloppe un BigInt entre -2 width-1 et 2 width-1 -1

Ces fonctions sont particulièrement utiles pour les opérations arithmétiques sur 64 bits. Ainsi, vous pouvez rester dans la plage prévue.

Support et transcription du navigateur

Au moment de la rédaction de ce document, Chrome +67 et Opera +54 prennent entièrement en charge le type de données BigInt . Malheureusement, Edge et Safari ne l’ont pas encore implémenté. Firefox ne prend pas en charge BigInt par défaut, mais vous pouvez l'activer en définissant javascript.options.bigint sur true dans à propos de: config . ]. Une liste à jour des navigateurs pris en charge est disponible sur Puis-je utiliser… .

Malheureusement, transpiler BigInt est un processus extrêmement compliqué qui encourt une lourde pénalité de performance au moment de l'exécution. Il est également impossible de procéder directement à la polyfill BigInt car la proposition modifie le comportement de plusieurs opérateurs existants. Pour le moment, une meilleure alternative consiste à utiliser la bibliothèque JSBI qui est une implémentation purement JavaScript de la proposition BigInt .

Cette bibliothèque fournit une API qui se comporte exactement de la même manière. comme l'indigène BigInt . Voici comment utiliser JSBI:

 importer JSBI depuis './jsbi.mjs';

const b1 = JSBI.BigInt (Number.MAX_SAFE_INTEGER);
const b2 = JSBI.BigInt ('10 ');

const résultat = JSBI.add (b1, b2);

console.log (String (résultat)); // → '9007199254741001'

L’avantage d’utiliser JSBI est qu’une fois la prise en charge du navigateur améliorée, vous n’avez plus besoin de réécrire votre code. Au lieu de cela, vous pouvez compiler automatiquement votre code JSBI en code BigInt natif à l’aide d’un plug-in babel . En outre, les performances de JSBI sont comparables à celles de l’application native BigInt . Vous pouvez vous attendre à une prise en charge plus large du navigateur pour BigInt

Conclusion

BigInt est un nouveau type de données destiné à être utilisé lorsque les valeurs entières sont supérieures à la plage prise en charge par Type de données Number . Ce type de données nous permet d'effectuer en toute sécurité des opérations arithmétiques sur des entiers de grande taille, de représenter des horodatages à haute résolution, d'utiliser des identificateurs d'entiers de grande taille, etc. sans avoir besoin d'utiliser une bibliothèque.

Il est important de garder à l'esprit que vous ne pouvez pas effectuer d'opérations arithmétiques. avec un mélange d'opérandes Number et BigInt . Vous devrez déterminer le domaine dans lequel l'opération doit être effectuée en convertissant explicitement l'un des opérandes. De plus, pour des raisons de compatibilité, vous n'êtes pas autorisé à utiliser l'opérateur unaire plus ( + ) sur un BigInt .

Qu'en pensez-vous? Trouvez-vous BigInt utile? Faites-le nous savoir dans les commentaires!

 Éditorial éclatant (dm, yk, il)






Source link