dr.Brain

doctor Brain

мир глазами веб-разработчика

Проблемы обработки валют в JavaScript

Осуществлять действия с валютами в JavaScript несколько сложнее, чем кажется

время чтения 3 мин.

Photo by Jonathan Brinkhorst on Unsplash

Денежные значения обычно представлены числами с плавающей запятой - и это проблема, так как умножение и деление становятся довольно сложными операциями. Если сомневаетесь, попробуйте ввести в консоли 10/3 или 3.3*3.

Конечно, иногда мы работаем с целыми числами, но гораздо чаще для представления фиатных валют нам требуются два знака после запятой, а при расчетах связанных с трейдингом или криптовалютами, после запятой могут потребоваться четыре, шесть, восемь и больше знаков.

Итак, нам нужно решить следующую проблему: как корректно делить и умножать действительные числа в JavaScript. Одно из решений - умножать действительное число на 10, пока оно не станет целым. Вместо того, чтобы умножать 3.3 на 3, можно умножить 33 на 3, а результат разделить на 10. Вот пример такого решения:

const multiplyMoney = (amount, multiplyBy, significantDecimals = 2) => {
    const precision = Math.pow(10, significantDecimals);
    const wholeAmount = amount * precision;
    const result = Math.floor(wholeAmount * multiplyBy);
    return result / precision;
};

Решение для деления носит сходный характер:

const divideMoney = (amount, divideBy, significantDecimals = 2) => {
    const precision = Math.pow(10, significantDecimals);
    const result = multiplyMoney(amount, 1 / divideBy, significantDecimals);
    const remainder = ((amount * precision) % (result * precision)) / precision;
    return [result, remainder];
};

console.log(3.111 * 2.1); // 6.533100000000001
console.log(multiplyMoney(3.111, 2.1, 6)); // 6.5331
console.log(multiplyMoney(3.111, 2.1)); // 6.53
console.log(10 / 3); // 3.3333333333333335
console.log(divideMoney(10, 3)); // [ 3.33, 0.01 ]
console.log(divideMoney(10, 3, 0)); // [ 3, 1 ]
console.log(divideMoney(10, 3, 1)); // [ 3.3, 0.1 ]

К счастью, давно прошли те дни, когда для корреткного отображения денежного значения нужно было добавлять строку с символом национальной валюты. Если Вы до сих пор так делаете, просто изучите API Intl.NumberFormat

Intl.NumberFormat - стандартный встроенный конструктор объектов JavaScript (дополнение к ядру ECMAScript), включающий языкозависимое форматирование.

Локаль определяет, как числа будут представлены для определенного языка. Некоторые языки используют запятую, чтобы отделить тысячи, и точку, чтобы отделить десятичные значение. У других языков все может быть наоборот:

  • США: 1,000,000.5
  • Индия: 1,00,00,000.5
  • Россия: 1 000,5

Валюта определяет символ, локаль - формат числового значения:

let number = 1000000.5;
let options = { style: 'currency', currency: 'USD' };

console.log(new Intl.NumberFormat('en-US', options).format(number));
// $1,000,000.50

console.log(new Intl.NumberFormat('in-IN', options).format(number));
// US$1.000.000,50

console.log(new Intl.NumberFormat('ru-RU', options).format(number));
// 1 000 000,50 $US

options = { style: 'currency', currency: 'EUR' };

console.log(new Intl.NumberFormat('en-US', options).format(number));
// €1,000,000.50

console.log(new Intl.NumberFormat('in-IN', options).format(number));
// €1.000.000,50

console.log(new Intl.NumberFormat('ru-RU', options).format(number));
// 1 000 000,50 €

Еще одно преимущество Intl.NumberFormat - это то, что данный конструктор входит в состав нативного API, а значит поддержка данного функционала браузерами будет осуществляться и развиваться в дальнейшем. А это одна из весомых причин, для того, чтобы использовать данный функционал в своем коде.


Спасибо за внимание.

Новые публикации

Далее

Категории

О нас

Frontend & Backend. Статьи, обзоры, заметки, код, уроки.