Come posso arrotondare un numero in JavaScript? .toFixed () restituisce una stringa?


176

Mi sto perdendo qualcosa qui?

var someNumber = 123.456;
someNumber = someNumber.toFixed(2);
alert(typeof(someNumber));
//alerts string

Perché non.toFixed()restituire una stringa?

Voglio arrotondare il numero a 2 cifre decimali.


7
Perché è progettato per restituire una stringa?
kennytm,

2
A me sembra strano. .toFixed () funziona solo sui numeri ... giusto?
Derek Adair,

10
Capisco Math.round () funziona come previsto. Stavo solo chiedendo perché una funzione che opera sui numeri restituisce una stringa ...
Derek Adair,

3
Le persone che vivono nel 2017 dovrebbero usare biblioteche come lodash.com/docs/4.17.4#ceil
Yves M.

1
Così fa _. contare? non ancora aggiornato a suo fratello.
Jenna Leaf,

Risposte:


124

Restituisce una stringa perché 0.1, e i suoi poteri (che sono usati per visualizzare le frazioni decimali), non sono rappresentabili (almeno non con la massima precisione) nei sistemi binari a virgola mobile.

Ad esempio, 0,1 è davvero 0,1000000000000000055511151231257827021181583404541015625 e 0,01 è davvero 0,010000000000000000008868681711721685132943093776702880859375. (Grazie per BigDecimalaver dimostrato il mio punto. :-P)

Pertanto (in assenza di un virgola mobile decimale o di un tipo di numero razionale), emetterlo come una stringa è l'unico modo per farlo tagliare esattamente alla precisione richiesta per la visualizzazione.


28
almeno javascript potrebbe salvarmi un po 'di lavoro con le dita e convertirlo in un numero ... sheesh ...
Derek Adair,

10
@Derek: Sì, ma una volta convertito in un numero, si verificano nuovamente gli stessi problemi di inesattezza. :-P JS non ha virgola mobile decimale o numeri razionali.
Chris Jester-Young,

1
@DerekAdair Di recente ho scritto un post che spiega ulteriormente questo, che potrebbe interessarti. Divertiti! stackoverflow.com/a/27030789/13
Chris Jester-Young,

7
In realtà questo mi ha fatto fare delle ricerche piuttosto pesanti su questo argomento! Grazie per tutto il vostro aiuto!
Derek Adair,

2
La tua risposta è leggermente fuorviante: toFixedè una funzione di formattazione, che ha il solo scopo di convertire un numero in una stringa, formattandolo utilizzando il numero specificato di decimali. Il motivo per cui restituisce una stringa è perché dovrebbe restituire una stringa e se invece fosse stata nominata toStringFixed, OP non sarebbe sorpreso dai risultati. L'unico problema qui è che OP si aspettava che funzionasse come Math.round, senza consultare il riferimento JS.
Groo,

177

Number.prototype.toFixedè una funzione progettata per formattare un numero prima di stamparlo. Viene dalla famiglia di toString, toExponentiale toPrecision.

Per arrotondare un numero, devi fare questo:

someNumber = 42.008;
someNumber = Math.round( someNumber * 1e2 ) / 1e2;
someNumber === 42.01;

// if you need 3 digits, replace 1e2 with 1e3 etc.
// or just copypaste this function to your code:

function toFixedNumber(num, digits, base){
  var pow = Math.pow(base||10, digits);
  return Math.round(num*pow) / pow;
}

.

Oppure, se si desidera una funzione " simile al nativo ", è possibile estendere il prototipo:

Number.prototype.toFixedNumber = function(digits, base){
  var pow = Math.pow(base||10, digits);
  return Math.round(this*pow) / pow;
}
someNumber = 42.008;
someNumber = someNumber.toFixedNumber(2);
someNumber === 42.01;


//or even hexadecimal

someNumber = 0xAF309/256  //which is af3.09
someNumber = someNumber.toFixedNumber(1, 16);
someNumber.toString(16) === "af3.1";

Tuttavia , tenere presente che l'inquinamento del prototipo è considerato negativo quando si scrive un modulo, poiché i moduli non dovrebbero avere effetti collaterali. Quindi, per un modulo, utilizzare la prima funzione .


12
Penso che questa sia la risposta migliore. Evita la conversione del tipo. Salsa stupenda!
Phil

1
Bella risposta! Tuttavia ... sto facendo JavaScript da circa 20 anni, ma non riesco a capire perché stai usando quella costruzione + (...) attorno al valore di ritorno? Grazie @sam per averlo massaggiato :) Dato che non sono mai troppo vecchio per imparare, ti preghiamo di elaborare :-)
HammerNL

1
@HammerNL Nonostante la convinzione di Sam, acutamente non fa nulla :) È solo una pratica - fa riconoscere agli IDE questa funzione type Number. Il fatto è che +(anyValue)restituisce sempre un numero, ad es. +("45")ritorna 45, +(new Number(42))ritorna 42. È un po 'come scrivere forte la funzione. Se ne
prendi l'

Perché questo non è inserito nel core javascript: s
webmaster

2
Il resuit di someNumber = Math.round( 42.008 * 1e2 ) / 1e2;non 42.01lo è, lo è ~42.0099999999999980. Motivo: il numero 42.01non esiste e viene arrotondato al numero esistente più vicino. tra l'altro, prova i numeri toPrecision(18)per stamparlo con tutte le cifre rilevanti.
Wiimm,

118

Ho risolto questo problema modificandolo:

someNumber = someNumber.toFixed(2)

...a questa:

someNumber = +someNumber.toFixed(2);

Tuttavia, questo convertirà il numero in una stringa e lo analizzerà di nuovo, il che avrà un impatto significativo sulle prestazioni. Se ti interessano le prestazioni o la sicurezza dei tipi, controlla anche le altre risposte.


39
No, no, no, no, no! Non farlo! La conversione da numero a stringa solo per arrotondarla è una pessima pratica ! Invece fallo someNumber = Math.round(someNumber * 1e2) / 1e2! Vedi la mia risposta per un modo più generalizzato.
m93a,

@ m93a - perché è una cattiva pratica?
jczaplew,

3
@jczaplew Perché se lo fai in questo modo, il numero binario a 32 bit viene convertito in una stringa, usando 16 bit per ogni cifra decimale maledetta ! (A proposito, la memorizzazione dei numeri in UTF-16 non è la cosa più conveniente per te.) E poi la stringa viene riconvertita in un numero in virgola mobile a 32 bit. Cifra per cifra. (Se ignoro tutti i test che devono essere eseguiti prima di scegliere l'algoritmo di analisi giusto.) E tutto ciò invano considerando che puoi farlo usando 3 operazioni veloci sul float.
m93a,

2
@ m93a quindi è per motivi di prestazioni? questo ha effettivamente un notevole impatto sulle prestazioni?
Sebastianb,

2
@jczaplew, Perché le stringhe sono (1) praticamente lente e (2) teoricamente errate.
Pacerier,

29

Perché non usare parseFloat?

var someNumber = 123.456;
someNumber = parseFloat(someNumber.toFixed(2));
alert(typeof(someNumber));
//alerts number

15

L'ho risolto convertendolo in numero usando la Number()funzione JavaScript

var x = 2.2873424;
x = Number(x.toFixed(2));

12

Ovviamente restituisce una stringa. Se si desidera arrotondare la variabile numerica, utilizzare invece Math.round (). Il punto di Fisso è formattare il numero con un numero fisso di posizioni decimali da visualizzare all'utente .


4

Puoi semplicemente usare un '+' per convertire il risultato in un numero.

var x = 22.032423;
x = +x.toFixed(2); // x = 22.03

3

Cosa ti aspetteresti che ritorni quando dovrebbe formattare un numero? Se hai un numero, non puoi praticamente farci nulla, ad es 2 == 2.0 == 2.00. Ecc., Quindi deve essere una stringa.


3

Per fornire un esempio del motivo per cui deve essere una stringa:

Se formatti 1.toFixed (2) otterrai '1.00'.

Questo non è uguale a 1, in quanto 1 non ha 2 decimali.


So che JavaScript non è esattamente un linguaggio delle prestazioni , ma è probabile che otterrai prestazioni migliori per un arrotondamento se usi qualcosa come: arrotondatoValore = Math.round (valore * 100) * 0,01


2

Perché il suo uso principale è la visualizzazione di numeri? Se si desidera arrotondare i numeri, utilizzare Math.round()con fattori appropriati.


ma visualizza NUMERI quindi non dovrebbe restituire un "numero"?
Derek Adair,

3
@Derek: solo nel modo in cui '42'è un numero ... che non lo è. Solo perché una stringa contiene solo cifre non la rende un numero. Questo non è PHP. :-P
Chris Jester-Young,

lol. Non è una stringa che contiene un numero ... È un numero che viene passato a un metodo. Il metodo accetta un numero e restituisce una stringa.
Derek Adair,

@DerekAdair giusto, ma un browser non può visualizzare un numero, visualizza stringhe, quindi la conversione.
Nick M,

1

Ecco una versione leggermente più funzionale della risposta m93afornita.

const toFixedNumber = (toFixTo = 2, base = 10) => num => {
  const pow = Math.pow(base, toFixTo)
  return +(Math.round(num * pow) / pow)
}

const oneNumber = 10.12323223

const result1 = toFixedNumber(2)(oneNumber) // 10.12
const result2 = toFixedNumber(3)(oneNumber) // 10.123

// or using pipeline-operator
const result3 = oneNumber |> toFixedNumber(2) // 10.12

è una funzione utile, per un tipo indefinito non funziona, ho aggiunto il codice per questo caso; if (num! == undefined) {return + (Math.round (num * pow) / pow)} else {return 0; }
Dino Liu,
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.