As the other answers have said, the problem is because toFixed
returns a string, then numero1
and numero2
will be strings. And when you use the operator +
string, they are concatenated and the result is another string.
In case, after calls from toFixed
, numero1
becomes the string '1.10'
and numero2
becomes '2.20'
. And when concatenating them, the result is the string '1.102.20'
:
let numero1 = '1,10';
numero1 = parseFloat(numero1.replace(/[^0-9,]*/g, '').replace(',', '.')).toFixed(2);
let numero2 = '2,20';
numero2 = parseFloat(numero2.replace(/[^0-9,]*/g, '').replace(',', '.')).toFixed(2);
console.log(numero1 + numero2); // 1.102.20
And this string, when passed to Math.round
, results in NaN
, since it is not a valid number (behavior described in the language specification). But just to be clear, contrary to what you said another answer, Math.round
can yes receive strings as parameter, provided that they represent valid numbers:
console.log(Math.round('1.23')); // 1
console.log(Math.round('7.9')); // 8
console.log(Math.round('-1234')); // -1234
console.log(Math.round('3.02e4')); // 30200 (número em notação científica)
console.log(Math.round('0xff')); // 255 (número em hexadecimal)
console.log(Math.round('')); // 0 (OK, esse é um caso "estranho", string vazia não deveria ser um "número válido", mas o JS acha que é...)
console.log(Math.round('1.102.20')); // NaN
console.log(Math.round('123xyz')); // NaN
Round or round off, that is the question
That said, the correct solution depends on several factors. It has an important detail that should be taken into account: the rounding. toFixed
, in addition to limiting the number of decimals, also round the value if necessary. Examples:
console.log(1.991.toFixed(2)); // '1.99'
console.log(2.999.toFixed(2)); // '3.00'
console.log(1.247.toFixed(2)); // '1.25'
console.log(1.244.toFixed(2)); // '1.24'
And in your case, it seems that you first want to round up the values (limiting them to 2 decimal places with toFixed
) and then add them up - and in the end round up the result with Math.round
. That is, if numero1
for '1,247'
and numero2
for '1,245'
, the result will be 3
:
function arredonda(n) {
n = parseFloat(n.replace(/[^0-9,]*/g, '').replace(',', '.')).toFixed(2);
// toFixed retorna uma string, então eu preciso converter para número de novo
return parseFloat(n);
}
let numero1 = '1,247';
numero1 = arredonda(numero1);
let numero2 = '1,245';
numero2 = arredonda(numero2);
console.log(numero1); // 1.25
console.log(numero2); // 1.25
console.log(numero1 + numero2); // 2.5
console.log(Math.round(numero1 + numero2)); // 3
But what if I didn’t round up the numbers, and just apply Math.round
in the final result? In that case the result would be 2
:
function converte(n) {
// não usa toFixed, retorna o número com todas as casas decimais
return parseFloat(n.replace(/[^0-9,]*/g, '').replace(',', '.'));
}
let numero1 = '1,247';
numero1 = converte(numero1);
let numero2 = '1,245';
numero2 = converte(numero2);
console.log(numero1); // 1.247
console.log(numero2); // 1.245
console.log(numero1 + numero2); // 2.492
console.log(Math.round(numero1 + numero2)); // 2
Another option would be to take only the first two decimal places of the numbers (without rounding) and the result would also be 2
:
function converte(n) {
n = parseFloat(n.replace(/[^0-9,]*/g, '').replace(',', '.'));
// em vez de toFixed, uso matemática para pegar somente as duas primeiras casas decimais
return Math.floor(n * 100) / 100;
}
numero1 = '1,247';
numero1 = converte(numero1);
numero2 = '1,245';
numero2 = converte(numero2);
console.log(numero1); // 1.24
console.log(numero2); // 1.24
console.log(numero1 + numero2); // 2.48
console.log(Math.round(numero1 + numero2)); // 2
That is, it is up to you to decide which approach to use. It is unclear whether all the values you receive always have exactly 2 houses after the comma. If so, then there is no rounding to be done and you wouldn’t even need to use toFixed(2)
. Just use the second option above, which only converts to number, without rounding anything. But if the number of decimals varies and can be greater than 2, the choice of one of the above approaches can make all the difference in the final result.
In fact, the first replace
It is unnecessary for these cases, as it removes everything that is neither number nor comma. But since the example strings only have numbers and a comma, then this replace
does nothing. But anyway, if the real data have other characters, then it makes more sense to use it, otherwise it could remove it without problems.
Money?
For this comment, hints that you are working on monetary values. If that is indeed the case, then the best is do not use floating point numbers (read more on the subject here). Instead, you can simply remove the comma and work with the total amount of cents. Then, when it’s time to display the value, then you format it the way you think best.
In the case of monetary values, you can even use Intl.NumberFormat
to format the value in a more "beautiful way":
function converteParaCentavos(n) {
// assumindo que o valor sempre tem 2 casas depois da vírgula,
//basta remover tudo que nao é número para ter a quantidade de centavos
return parseFloat(n.replace(/[^0-9]*/g, ''));
}
// converte tudo para centavos
numero1 = '1,24';
numero1 = converteParaCentavos(numero1);
numero2 = '1,24';
numero2 = converteParaCentavos(numero2);
console.log(numero1); // 124
console.log(numero2); // 124
console.log(numero1 + numero2); // 248
// somente na hora de mostrar, eu divido por 100 para mostrar o valor em reais
console.log(Math.round((numero1 + numero2) / 100)); // 2
// exemplo com Intl.NumberFormat
let formatter = new Intl.NumberFormat('pt-BR', {
style: 'currency',
currency: 'BRL',
});
// sem arredondar
console.log(formatter.format((numero1 + numero2) / 100)); // R$ 2,48
// arredondando
console.log(formatter.format(Math.round((numero1 + numero2) / 100))); // R$ 2,00
No return Nan...
– Daniel Mendes
Pressing the result gives 3.
– Augusto Vasques
Probably some problem related to the environment in which you are running the code.
– G. Bittencourt
Edited, sorry, no code.
– ElvisP
After converting the two numbers into string the operator
+
works as a concatenator.– Augusto Vasques