Эта статья была первоначально написана Джулио Сампайо на BoneyBadger Developer Blog Отказ
Одной из самых любопытных вещей о современных языках программирования является то, что когда кто-то решит создать новую, много мышления о принятых типах данных и внутренних вспомогательных библиотеках происходит.
Подумайте обо всех языках программирования, с которыми вы работали раньше. Сколько способов иметь дело с датами и временами у них? Большинство из них, вероятно, будут выпустить по крайней мере один способ справиться с такими типами данных, поскольку он является очень поданным в жизни программирования разработчика.
Что случилось с деньгами, то тогда? Банки, брокеры, интернет-магазины и т. Д. Нужно программно справляться с деньгами. И это было так долго.
Из-за отсутствия представительной способности типы денег обрабатываются во многих отношениях, в зависимости от языка, который вы используете. Следовательно, некоторые подводные камни появляются.
В этой статье мы подробно рассмотрим эти общие подводные камни и лучшие варианты смягчения с деньгами в JavaScript.
Комминты подводные камни
Прежде чем мы погрузимся в подводные камни, давайте сначала поймем, что требуется для выполнения денежных расчетов.
С 2002 года, когда Мартин Фаулер выпустил свою признанную книгу под названием Шаблоны архитектуры приложения предприятия у нас есть Отличная модель иметь дело с денежными ценностями. Все это сводится к двум свойствам, количество и валюта И несколько ожидаемых операций, в том числе _ +, -, *,/,>,> =, <, <= и =.
Подумайте о них немного. Если мы прекратим видеть деньги как простое число и начать просмотр его в качестве структуры данных, состоящей из двух важных свойств, и некоторые методы для решения сравнения, преобразования и расчетов, то мы решаем большинство проблем, связанных с этим типом данных.
Другими словами, делать денежные расчеты, вам всегда понадобится сумма и валюта, а также способ выполнения операций на них (I.E., через методы/функции).
С точки зрения JavaScript, A Деньги
Объект, который может, например, удерживать два реквизита и подвергать некоторые функции для расчетов будут выполнять работу.
Не используйте плавающую точку
При работе с деньгами вам нужно также хранить центы. Для многих разработчиков, хранение таких ценностей в десятичные числа – это правильное решение, потому что есть десятичные места.
Обычно они представлены как единица мощности 10:
10² = 100 cents in a dollar 10³ = 1000 cents in 10 dollars ...
Однако, представляя деньги в качестве номеров с плавающей точкой в компьютере, представляют некоторые проблемы, как мы видели здесь Отказ
Числа с плавающей точкой существуют через Различная арифметика на твоем компьютере. Поскольку ваш компьютер использует бинарную систему для хранения десятичных чисел, вы в конечном итоге вы получите несовместимые результаты с вашими расчетами:
0.2233 + 0.1 // results in 0.32330000000000003
Это происходит, потому что компьютер пытается закруглить столько, сколько может получить лучший результат. Это также отключает числа, которые слишком велики, такие как периодические десятины, например.
Вы можете принять решение о приведении результата предыдущей операции самостоятельно, например, Math.Ceil
:
Math.ceil(0.2233 + 0.1) // results in 1
Однако этот подход все равно будет проблематичным, потому что вы потеряете пару пенни во время процесса. В зависимости от типа приложения вы разрабатываетесь, потери, как это может представлять много потерянных денег для клиентов или вашего бизнеса.
Из-за этих проблем, представляющих деньги как плавать Объект не рекомендуется. Если вы все еще заинтересованы в том, чтобы узнать больше о специфике этого вопроса, я настоятельно рекомендую прочитать статью Oracle: Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой Отказ
Не используйте номер Либо
Как на многих других языках, а Номер
является примитивным объектом обертки, который используется, когда разработчики должны представлять или манипулировать числами, от целых чисел до десятичных средств.
Кроме того, потому что это Двухточная 64-битный двоичный формат IEEE 754 Значение, это также представляет такую же угрозу, о которой мы просто говорили в предыдущем разделе.
Кроме того, Номер
Также не хватает одного из условий Фаулера для создания идеальной денежной структуры: валюта Отказ Это было бы отлично, если ваша заявка в настоящее время имеет дело только с одной валютой. Однако это может быть опасно, если вещи меняются в будущем.
INTL API.
API интернационализации Ecmascript это коллективное усилие для обеспечения стандартизированного форматирования для международных целей. Это позволяет приложениям решать, какие функции им нужны и как их приблизится.
Среди предоставленных множества функций у нас есть форматирование номеров, что также охватывает форматирование денежных средств на основе указанного языка.
Взгляните на следующий пример:
var formatterUSD = new Intl.NumberFormat('en-US'); var formatterBRL = new Intl.NumberFormat('pt-BR'); var formatterJPY = new Intl.NumberFormat('ja-JP'); console.log(formatterUSD.format(0.2233 + 0.1)); // logs "0.323" console.log(formatterBRL.format(0.2233 + 0.1)); // logs "0,323" console.log(formatterJPY.format(0.2233 + 0.1)); // logs "0.323"
Мы создаем три разных форматтера, проходящие различные локали для нас, бразильских и японских валют, соответственно. Это здорово видеть, насколько мощный этот API с точки зрения охвата как суммы, так и в валюте одновременно и выполняет гибкие расчеты на них.
Обратите внимание, как десятичная система меняется из одной страны в другую и как Intl API правильно рассчитала результат нашей денежной суммы для всех различных валют.
Если вы хотите установить максимальное количество значительных цифр, просто измените код:
var formatterUSD = new Intl.NumberFormat('en-US', { maximumSignificantDigits: 2 }); console.log(formatterUSD.format(0.2233 + 0.1)); // logs "0.32"
Это то, что обычно происходит, когда вы платите за газ на заправке.
API может даже позволить вам отформатировать денежную стоимость, включая валютный знак конкретной страны:
var formatterJPY = new Intl.NumberFormat('ja-JP', { maximumSignificantDigits: 2, style: 'currency', currency: 'JPY' }); console.log(formatterJPY.format(0.2233 + 0.1)); // logs "¥0.32"
Кроме того, это позволяет преобразование различных форматов, таких как скорость (например, километр-в час) и том (например, _Liters ). При этом ссылка , вы можете найти все доступные варианты для INTL NumberFormat
Отказ
Тем не менее, важно обратить внимание на Совместимость браузера Ограничения этой особенности. Поскольку это стандарт, некоторые версии браузера не будут поддерживать часть своих вариантов, таких как Internet Explorer и Safari.
Для этих случаев последовочный подход будет приветствовать, если вы готовы поддержать ваше приложение на этих веб-браузерах.
Dinero.js, валюта.js и номера.
Тем не менее, всегда есть отличные библиотеки, которые сообщество развивает для поддержки недостающих функций, таких как dinero.js , валюта.js и Numeral.js Отказ
На рынке доступнее, но мы сосредоточимся на этих трех, потому что они представляют значительный процент разработчиков с использованием функций форматирования валюты.
Dinero.js.
Dinero.js – это легкая, неизменная и цепимальная библиотека JavaScript, разработанная для работы с денежными значениями и включает глобальные настройки, расширенные варианты форматирования/округления, удобные преобразования валюты и нативную поддержку для Intl.
Установка это так просто, как запуск одной команды:
npm install dinero.js
Одним из величайших преимуществ использования этой библиотеки является то, что он полностью охватывает определение денег Фаулера, что означает, что он поддерживает как количество, так и ценности валюты:
const money = Dinero({ amount: 100, currency: 'USD' })
Кроме того, он также предоставляет методы по умолчанию для решения денежных расчетов:
const tax = Dinero({ amount: 10, currency: 'USD' }) const result = money.subtract(tax) // returns new Dinero object console.log(result.getAmount()) // logs 90
Важно заявить, что Dinero.js не имеет дело с центами отдельно. Суммы указаны в небольших валютных единицах, в зависимости от используемой вами валюты. Если вы используете USD, то деньги представлены в центах.
Чтобы помочь с частью форматирования, она предоставляет нам Toformat ()
Способ, который получает строку с шаблоном валюты, с которой вы хотели бы отформатировать:
Dinero({ amount: 100 }).toFormat('$0,0') // logs "$1" Dinero({ amount: 100000 }).toFormat('$0,0.00') // logs "$1,000.00"
Вы контролируете, как библиотека обрабатывает форматы. Например, если вы имеете дело с валютами, которые имеют другой экспонент (то есть более двух десятичных знаков), вы можете явно определить точность, как показано ниже:
Dinero({ amount: 100000, precision: 3 }).toFormat('$0,0.000') // logs "$100.000" Dinero({ amount: 100, currency: 'JPY', precision: 0 }).toFormat() // logs "¥100.00"
Возможно, одна из его самых больших функций – это цепочковая поддержка для его методов, что приводит к лучшему читабельности и техническому обслуживанию кода:
Dinero({ amount: 10000, currency: 'USD' }) .add(Dinero({ amount: 20000, currency: 'USD' })) .divide(2) .percentage(50) .toFormat() // logs "$75.00"
Dinero.js также предоставляет способ создания локального или удаленного преобразования Exchange через его конвертировать метод. Вы можете либо получать данные обмена от внешнего API для отдыха, либо настроить локальную базу данных с файлом JSON, который Dinero.js может использовать для выполнения преобразований.
Валюта.js.
Vaulty.js – очень маленькая (всего 1,14 КБ) библиотека JavaScript для работы с валютными значениями.
Чтобы решить проблему с плавающей точкой, о которой мы говорили, валюта .JS работает с целыми числами за кулисами и гарантирует, что десятичная точность всегда правильная.
Чтобы установить его, вам просто нужна одна команда:
npm install currency.js
Библиотека может быть еще менее Verbose, чем Dinero.js, путем инкапсулирования денежной стоимости (будь то строка, десятичная, число или валюта) в ее валюта ()
объект:
currency(100).value // logs 100
API очень чистый и простой, так как он также принимает цепочный стиль:
currency(100) .add(currency("$200")) .divide(2) .multiply(0.5) // simulates percentage .format() // logs "$75.00"
Он также принимает строковые параметры, такие как денежное значение, со знаком, как видно выше. Формат ()
Метод, в свою очередь, возвращает человеческий формат валюты.
Тем не менее, когда дело доходит до интернационализации, валюта. JS по умолчанию в Базалии США. Если вы готовы работать с другими валютами, должна быть сделана дополнительная работа:
const USD = value => currency(value); const BRL = value => currency(value, { symbol: 'R$', decimal: ',', separator: '.' }); const JPY = value => currency(value, { precision: 0, symbol: '¥' }); console.log(USD(110.223).format()); // logs "$110.22" console.log(BRL(110.223).format()); // logs "R$110,22" console.log(JPY(110.223).format()); // logs "¥110"
Vaulty.js чище, чем dinero.js с точки зрения извлеченности, что отлично. Тем не менее, у него нет встроенного для преобразования Exchange, поэтому будьте в курсе этого ограничения, если ваше приложение должно сделать это.
Цифру
Как предполагает название библиотеки, цифру .js – это больше библиотеки общего назначения, которая касается форматирования и манипулирования номерами в целом в JavaScript.
Хотя он также может манипулировать ценностями валюты, он предлагает очень гибкий API для создания Пользовательские форматы Отказ
Чтобы установить его, требуется только одна команда:
npm install numeral
Его синтаксис очень похож на value.js при инкапсулировании денежной стоимости в его цифру ()
объект:
numeral(100).value() // logs 100
Когда дело доходит до форматирования этих значений, он ближе к синтаксису Dinero.js:
numeral(100).format('$0,0.00') // logs "$100.00"
Так как библиотека ограничена Встроенный Особенности интернационализации, вам придется установить на случай, если нужна новая валютная система:
numeral.register('locale', 'es', { delimiters: { thousands: ' ', decimal: ',' }, currency: { symbol: '€' } }) numeral.locale('es') console.log(numeral(10000).format('$0,0.00')) // logs "€10 000,00"
Когда дело доходит до цепочманного рисунка, номера .JS также доставляет одинаковую читаемость, которую мы ищем:
const money = numeral(100) .add(200) .divide(2) .multiply(0.5) // simulates percentage .format('$0,0.00') // logs "$75.00"
Numeral.js, безусловно, самая гибкая библиотека для решения номеров в нашем списке. Его гибкость включает в себя мощность для создания локалей и форматов по желанию. Тем не менее, будьте осторожны при использовании его, поскольку он не обеспечивает способ по умолчанию для расчета с нулевой точностью для десятичных чисел.
Упаковка
В этом посте в блоге мы исследовали некоторые из лучших альтернатив, чтобы иметь дело с денежными значениями в JavaScript, будь то для клиентов или в ответных приложений. Давайте переведем некоторые важные моменты, которые обсуждаются до сих пор:
- Если вы имеете дело с деньгами, никогда не используйте примитивное число с плавающей точкой языка или
Номер
объект обертки. - Вместо этого INTL API, предоставленная по умолчанию вашего веб-браузера, является предпочтительным. Это более гибкий, безопасный и умный. Однако будьте в курсе своих ограничений совместимости.
- Независимо от каждого, если вы можете добавить немного больше веса в свой приложение, рассмотрите возможность принятия одной из продемонстрированных библиотек при работе с расчетами валюты и/или преобразования.
Наконец, обязательно обратитесь к своим официальным документам и тестам. Большинство из них предоставляют отличные тесты, чтобы помочь вам понять плюсы и минусы каждой библиотеки и выбрать тот, который наилучшим образом подходит для ваших потребностей.
Оригинал: “https://dev.to/honeybadger/currency-calculations-in-javascript-dnk”