Як я можу округляти номер у JavaScript? .toFixed () повертає рядок?


176

Я щось тут пропускаю?

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

Чому ж.toFixed()повертає рядок?

Я хочу округлити число до двох десяткових цифр.


7
Тому що він призначений для повернення рядка?
kennytm

2
Мені це здається дивним. .toFixed () працює лише на числах ... правда?
Дерек Адаїр

10
Я розумію, що Math.round () працює як очікувалося. Я просто розпитував, чому функція, яка працює на числа, повертає рядок ...
Дерек Адаїр

3
Люди, які живуть у 2017 році, повинні використовувати такі бібліотеки, як lodash.com/docs/4.17.4#ceil
Ів М.

1
Так і _. рахувати? ще не модернізований до свого брата.
Jenna Leaf

Відповіді:


124

Він повертає рядок, оскільки 0,1 та його повноваження (які використовуються для відображення десяткових дробів) не є представними (принаймні, не з повною точністю) у двійкових системах з плаваючою комою.

Наприклад, 0,1 дійсно 0,1000000000000000055511151231257827021181583404541015625, а 0,01 дійсно 0,01000000000000000020816681711721685132943093776702880859375. (Дякую BigDecimalза те, що ви довели свою думку. :-P)

Тому (відсутня десяткова плаваюча точка чи раціональний тип числа), виведення його у вигляді рядка - єдиний спосіб налагодити його точно до точності, необхідної для відображення.


28
принаймні javascript міг би врятувати мене пальцевою роботою і перетворити її на номер ... sheesh ...
Дерек

10
@Derek: Так, але як тільки ти перетвориш його назад у число, ти знову зіткнешся з тими самими проблемами неточності. :-P JS не має десяткової плаваючої крапки або раціональних чисел.
Кріс Єстер-Янг

1
@DerekAdair Нещодавно я написав пост, який ще більше пояснює це, що вас може зацікавити. Насолоджуйтесь! stackoverflow.com/a/27030789/13
Кріс Шестер-Янг

7
Насправді це змусило мене зробити досить важкі дослідження з цього питання! дякую за всю вашу допомогу!
Дерек Адаїр

2
Ваша відповідь трохи вводить в оману: toFixedце функція форматування, яка має єдину мету перетворити число в рядок, відформатувавши його за допомогою вказаної кількості десяткових знаків. Причина, по якій він повертає рядок, полягає в тому, що вона повинна повернути рядок, і якби вона була назначена toStringFixedзамість, ОП не буде здивована результатами. Єдине питання тут полягає в тому, що ОП очікувала, що це буде працювати Math.round, не звертаючись до посилань на JS.
Гроо

177

Number.prototype.toFixed- це функція, призначена для форматування числа перед його надрукуванням. Це з родини toString, toExponentialі toPrecision.

Щоб округлити число, ви зробите це:

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;
}

.

Або якщо ви хочете функцію "на зразок ", ви можете продовжити прототип:

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";

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


12
Я думаю, що це найкраща відповідь. Це дозволяє уникнути перетворення типів. Дивовижний соус!
Філ

1
Чудова відповідь! Однак ... я займаюся JavaScript приблизно 20 років, але я не можу зрозуміти, чому ви використовуєте цю конструкцію + (...) навколо повернутого значення? Дякую @sam за те, що його вбрали :) Оскільки я ніколи не старий, щоб навчитися, будь ласка, докладно :-)
HammerNL

1
@HammerNL Незважаючи на переконання Сема, він гостро нічого не робить :) Це просто практика - це змушує IDE визнати цю функцію як type Number. Вся справа в тому, що +(anyValue)завжди повертає число - наприклад. +("45")повертає 45, +(new Number(42))повертає 42. Це якось як сильне введення функції. Якщо ви звикли до цього, ви можете уникнути безлічі помилок :)
m93a

Чому це не запікається в основний javascript: s
webmaster

2
Повторне виконання someNumber = Math.round( 42.008 * 1e2 ) / 1e2;не є 42.01, воно є ~42.0099999999999980. Причина: число 42.01не існує і округляється до найближчого існуючого числа. btw, перевірити номери, toPrecision(18)щоб надрукувати його з усіма відповідними цифрами.
Wiimm

118

Я вирішив цю проблему, змінивши це:

someNumber = someNumber.toFixed(2)

...до цього:

someNumber = +someNumber.toFixed(2);

Однак це перетворить число в рядок і проаналізує його знову, що матиме значний вплив на продуктивність. Якщо ви дбаєте про продуктивність або безпеку типу, перевірте також інші відповіді.


39
Ні, ні, ні, ні, ні! Не робіть цього! Перетворення рядків на рядок просто для круглого - це дуже погана практика ! Замість цього робіть someNumber = Math.round(someNumber * 1e2) / 1e2! Дивіться мою відповідь більш узагальнено.
m93a

@ m93a - чому це така погана практика?
jczaplew

3
@jczaplew Тому що, якщо ви зробите це так, 32-бітове двійкове число перетворюється в рядок, використовуючи 16 біт для кожної чортової десяткової цифри ! (До речі, зберігання чисел у UTF-16 - це не найзручніша річ, яку ви б хотіли зробити.) І ніж рядок перетворюється назад на 32-бітове число з плаваючою комою. Цифру за цифрою. (Якщо я ігнорую всі тести, які необхідно зробити перед тим, щоб обрати правильний алгоритм розбору.) І все це даремно, враховуючи, що ви можете зробити це за допомогою 3 швидких операцій на плаву.
m93a

2
@ m93a, тому це з міркувань продуктивності? чи це насправді має помітний вплив на продуктивність?
Себастьянб

2
@jczaplew, Тому що струни (1) практично повільні і (2) теоретично неправильні.
Pacerier


15

Я вирішив це, перетворивши його на номер за допомогою Number()функції JavaScript

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

12

Звичайно, він повертає рядок. Якщо ви хочете округлити числову змінну, замість цього скористайтеся Math.round (). Сенс toFixed полягає у форматуванні числа з фіксованою кількістю десяткових знаків для відображення користувачеві .


4

Ви можете просто скористатися "+", щоб перетворити результат у число.

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

3

Що ви очікуєте, що воно повернеться, коли він повинен відформатувати число? Якщо у вас є номер, ви не можете з ним зробити нічого, тому що, наприклад, 2 == 2.0 == 2.00тощо, це повинно бути рядком.


3

Щоб навести приклад того, чому це повинно бути рядок:

Якщо ви відформатуєте 1.toFixed (2), ви отримаєте "1.00".

Це не те саме, що 1, оскільки 1 не має 2 десяткових знаків.


Я знаю, що JavaScript не є точно мовою продуктивності , але, швидше за все, ви отримаєте кращу ефективність для округлення, якщо використовуєте щось на кшталт: roundedValue = Math.round (значення * 100) * 0,01


2

Тому що його основне використання - це відображення цифр? Якщо ви хочете округлювати числа, використовуйте Math.round()відповідні коефіцієнти.


але він відображає НОМЕРИ, так чи не повинен він повертати "число"?
Дерек Адаїр

3
@Derek: Тільки таким чином, що '42'це число ... чого це не так. Просто через те, що рядок містить лише цифри, це не робить його числом. Це не PHP. :-P
Кріс Єстер-Янг

Лол. Це не рядок, який містить число ... Це число, яке передається методу. Метод приймає число і повертає рядок.
Дерек Адаїр

@DerekAdair справа, але браузер не може відображати число, він відображає рядки, таким чином, перетворення.
Нік М

1

Ось трохи більш функціональна версія m93aнаданої відповіді .

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

це зручна функція, для невизначеного типу вона не працює, я додав код для цього випадку; if (num! == undefined) {return + (Math.round (num * pow) / pow)} else {return 0; }
Діно Лю
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.