Làm cách nào tôi có thể làm tròn số trong JavaScript? .toFixed () trả về một chuỗi?


176

Am i thiếu cái gì ở đây?

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

Tại sao không.toFixed()trả về một chuỗi?

Tôi muốn làm tròn số đến 2 chữ số thập phân.


7
Bởi vì nó được thiết kế để trả về một chuỗi?
kennytm

2
Đối với tôi nó chỉ có vẻ kỳ quặc. .toFixed () chỉ hoạt động trên các số ... phải không?
Derek Adair

10
Tôi hiểu Math.round () hoạt động như mong đợi. Tôi chỉ đang hỏi tại sao một hàm hoạt động trên các số lại trả về một chuỗi ...
Derek Adair

3
Những người sống trong năm 2017 nên sử dụng các thư viện như lodash.com/docs/4.17.4#ceil
Yves M.

1
_ đếm? chưa nâng cấp lên bro của mình.
Lá Jenna

Câu trả lời:


124

Nó trả về một chuỗi vì 0,1 và sức mạnh của nó (được sử dụng để hiển thị phân số thập phân), không thể biểu diễn (ít nhất là không có độ chính xác đầy đủ) trong các hệ thống dấu phẩy động nhị phân.

Ví dụ: 0,1 thực sự là 0,000000000000000055511151231257827021181583404541015625 và 0,01 thực sự là 0,01000000000000000020816681711721685132943093776702880859375. (Cảm ơn BigDecimalvì đã chứng minh quan điểm của tôi. :-P)

Do đó (không có dấu phẩy động thập phân hoặc loại số hữu tỷ), xuất ra nó dưới dạng chuỗi là cách duy nhất để làm cho nó được cắt theo chính xác độ chính xác cần thiết để hiển thị.


28
ít nhất javascript có thể giúp tôi tiết kiệm một số công việc ngón tay và chuyển nó trở lại thành một số ... sheesh ...
Derek Adair

10
@Derek: Vâng, nhưng một khi bạn chuyển đổi nó thành một số, bạn lại gặp vấn đề không chính xác. :-P JS không có dấu phẩy động thập phân hoặc số hữu tỷ.
Chris Jester-Young

1
@DerekAdair Gần đây tôi đã viết một bài viết giải thích điều này hơn nữa, mà bạn có thể quan tâm. Hãy tận hưởng! stackoverflow.com/a/27030789/13
Chris Jester-Young

7
Thật ra điều này khiến tôi phải thực hiện một số nghiên cứu khá nặng nề về chủ đề này! Cảm ơn tất cả sự giúp đỡ của bạn!
Derek Adair

2
Câu trả lời của bạn hơi sai lệch: toFixedlà một chức năng định dạng, có mục đích duy nhất là chuyển đổi một số thành một chuỗi, định dạng nó bằng cách sử dụng số thập phân được chỉ định. Lý do nó trả về một chuỗi là vì nó được cho là trả về một chuỗi và nếu nó được đặt tên toStringFixedthay thế, OP sẽ không ngạc nhiên với kết quả. Vấn đề duy nhất ở đây là OP mong đợi nó hoạt động như thế nào Math.round, mà không cần tham khảo tài liệu tham khảo JS.
Groo

176

Number.prototype.toFixedlà một chức năng được thiết kế để định dạng một số trước khi in ra. Đó là từ gia đình của toString, toExponentialtoPrecision.

Để làm tròn một số, bạn sẽ làm điều này:

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

.

Hoặc nếu bạn muốn một chức năng giống như bản địa của người Viking , bạn có thể mở rộng nguyên mẫu:

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

Tuy nhiên , hãy nhớ rằng việc gây ô nhiễm nguyên mẫu được coi là xấu khi bạn viết mô-đun, vì các mô-đun không nên có bất kỳ tác dụng phụ nào. Vì vậy, đối với một mô-đun, sử dụng chức năng đầu tiên .


12
Tôi nghĩ rằng đây là câu trả lời tốt nhất. Nó tránh chuyển đổi loại. Rất tuyệt vời!
Phil

1
Câu trả lời chính xác! Tuy nhiên ... Tôi đã làm JavaScript khoảng 20 năm hoặc lâu hơn, nhưng tôi không thể hiểu tại sao bạn lại sử dụng cấu trúc + (...) đó xung quanh giá trị trả về? Cảm ơn @sam đã cọ xát nó vào :) Vì tôi không bao giờ quá già để học, xin hãy giải thích :-)
HammerNL

1
@ HammerNL Mặc dù niềm tin của Sam, nhưng thực tế nó không làm gì cả :) Đó chỉ là một thực tế - nó làm cho các IDE nhận ra chức năng này là type Number. Điều này là +(anyValue)luôn trả về một số - ví dụ. +("45")trả lại 45, +(new Number(42))trả lại 42. Nó giống như gõ mạnh chức năng. Nếu bạn tạo thói quen cho nó, bạn có thể tránh được rất nhiều lỗi :)
m93a

Tại sao điều này không được đưa vào javascript cốt lõi: s
quản trị trang web

2
Việc bán lại someNumber = Math.round( 42.008 * 1e2 ) / 1e2;không phải 42.01là nó ~42.0099999999999980. Lý do: Số 42.01không tồn tại và được làm tròn đến số hiện có gần nhất. btw, số bằng chứng toPrecision(18)để in nó với tất cả các chữ số có liên quan.
Wiimm

118

Tôi đã giải quyết vấn đề này bằng cách thay đổi điều này:

someNumber = someNumber.toFixed(2)

... đến đây:

someNumber = +someNumber.toFixed(2);

Tuy nhiên, điều này sẽ chuyển đổi số thành một chuỗi và phân tích lại nó, điều này sẽ có tác động đáng kể đến hiệu suất. Nếu bạn quan tâm đến hiệu suất hoặc loại an toàn, hãy kiểm tra các câu trả lời khác.


39
Không không không không không! Đừng làm vậy! Chuyển đổi số thành chuỗi chỉ để làm tròn nó là một thực tế rất xấu ! Thay vào đó hãy làm someNumber = Math.round(someNumber * 1e2) / 1e2! Xem câu trả lời của tôi cho một cách tổng quát hơn.
m93a

@ m93a - Tại sao nó thực hành tồi như vậy?
jczaplew

3
@jczaplew Bởi vì nếu bạn làm theo cách này, số nhị phân 32 bit được chuyển đổi thành một chuỗi, sử dụng 16 bit cho mỗi chữ số thập phân chết tiệt ! (Bằng cách lưu trữ số trong UTF-16 không phải là điều thuận tiện nhất bạn muốn.) Và hơn cả chuỗi được chuyển đổi thành số dấu phẩy động 32 bit. Chữ số bằng chữ số. (Nếu tôi bỏ qua tất cả các thử nghiệm phải được thực hiện trước đó để chọn thuật toán phân tích cú pháp phù hợp.) Và tất cả những điều đó vô ích khi xem xét bạn có thể thực hiện bằng 3 thao tác nhanh trên float.
m93a

2
@ m93a vậy là vì lý do hiệu suất? điều này thực sự có tác động đáng chú ý trong hiệu suất?
Sebastianb

2
@jczaplew, Bởi vì Chuỗi (1) thực tế chậm và (2) về mặt lý thuyết không chính xác.
Pacerier

28

Tại sao không sử dụng parseFloat?

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

15

Tôi đã giải quyết nó bằng cách chuyển đổi nó trở lại số bằng Number()hàm JavaScript.

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

12

Tất nhiên nó trả về một chuỗi. Nếu bạn muốn làm tròn biến số, bạn sẽ sử dụng Math.round (). Điểm của toFixed là định dạng số có số vị trí thập phân cố định để hiển thị cho người dùng .


4

Bạn chỉ có thể sử dụng '+' để chuyển đổi kết quả thành số.

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

3

Bạn mong đợi điều gì sẽ trở lại khi định dạng số? Nếu bạn có một số, bạn không thể làm bất cứ điều gì với nó vì 2 == 2.0 == 2.00v.v. vì vậy nó phải là một chuỗi.


3

Để cung cấp một ví dụ về lý do tại sao nó phải là một chuỗi:

Nếu bạn định dạng 1.toFixed (2), bạn sẽ nhận được '1,00'.

Điều này không giống với 1, vì 1 không có 2 số thập phân.


Tôi biết JavaScript không chính xác là ngôn ngữ hiệu suất , nhưng rất có thể bạn sẽ có hiệu suất tốt hơn để làm tròn nếu bạn sử dụng thứ gì đó như: roundValue = Math.round (value * 100) * 0,01


2

Bởi vì sử dụng chính của nó là hiển thị số? Nếu bạn muốn làm tròn số, sử dụng Math.round()với các yếu tố phù hợp.


nhưng nó đang hiển thị SỐ SỐ vì vậy nó không nên trả về "số"?
Derek Adair

3
@Derek: Chỉ theo cách đó '42'là một con số ... mà không phải vậy. Chỉ vì một chuỗi xảy ra chỉ chứa các chữ số không làm cho nó thành một số. Đây không phải là PHP. :-P
Chris Jester-Young

cười lớn. Đây không phải là một chuỗi chứa một số ... Đó là một số được truyền cho một phương thức. Phương thức lấy một số và trả về một chuỗi.
Derek Adair

@DerekAdair đúng nhưng trình duyệt không thể hiển thị Số, nó hiển thị chuỗi, do đó, chuyển đổi.
Nick M

1

Đây là một phiên bản chức năng hơn một chút của câu trả lời m93ađược cung cấp.

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

Đó là chức năng tiện dụng, đối với loại không xác định, nó không hoạt động, tôi đã thêm mã cho trường hợp này; if (num! == không xác định) {return + (Math.round (num * pow) / pow)} other {return 0; }
Dino Liu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.