ฉันจะปัดเศษตัวเลขใน JavaScript ได้อย่างไร .toFixed () ส่งคืนสตริงหรือไม่


176

ฉันทำอะไรบางอย่างหายไปหรือเปล่า

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

ทำไมไม่.toFixed()กลับสตริง?

ฉันต้องการปัดเศษทศนิยมเป็น 2 หลัก


7
เพราะมันถูกออกแบบมาเพื่อส่งกลับสตริง?
kennytm

2
สำหรับฉันมันดูเหมือนแปลก ๆ .toFixed () ทำงานเฉพาะกับตัวเลข ... ใช่ไหม
Derek Adair

10
ฉันเข้าใจ Math.round () ทำงานตามที่คาดไว้ ฉันแค่ถามว่าทำไมฟังก์ชั่นที่ทำงานกับตัวเลขส่งคืนสตริง ...
Derek Adair

3
ผู้คนที่อาศัยอยู่ในปี 2560 ควรใช้ห้องสมุดเช่นlodash.com/docs/4.17.4#ceil
Yves M.

1
ดังนั้น _ นับ? ยังไม่อัปเกรดเป็นพี่ชายของเขา
เจนน่าลีฟ

คำตอบ:


124

มันส่งกลับสตริงเพราะ 0.1 และอำนาจของมัน (ซึ่งใช้ในการแสดงเศษส่วนทศนิยม) จะไม่สามารถแทนได้ (อย่างน้อยก็ไม่ได้มีความแม่นยำเต็มรูปแบบ) ในระบบเลขทศนิยม

ตัวอย่างเช่น 0.1 คือ 0.100000000000000000055511151231257827021181583404541015625 จริง ๆ และ 0.01 คือจริง ๆ 0.01000000000000000000816681711721685132943093776702880859375 (ขอบคุณBigDecimalสำหรับการพิสูจน์จุดของฉัน :-P)

ดังนั้น (ไม่มีทศนิยมทศนิยมหรือประเภทจำนวนตรรกยะ), เอาท์พุทมันเป็นสตริงเป็นวิธีเดียวที่จะได้รับมันถูกตัดให้แม่นยำที่จำเป็นสำหรับการแสดงผล


28
อย่างน้อยจาวาสคริปต์สามารถช่วยฉันทำงานนิ้วและแปลงกลับเป็นตัวเลข ... sheesh ...
Derek Adair

10
@Derek: ใช่ แต่เมื่อคุณแปลงกลับเป็นตัวเลขคุณจะพบปัญหาความไม่ถูกต้องเหมือนเดิมอีกครั้ง :-P JS ไม่มีทศนิยมทศนิยมหรือจำนวนตรรกยะ
Chris Jester-Young

1
@DerekAdair ฉันเพิ่งเขียนโพสต์ที่จะอธิบายสิ่งนี้ให้ดียิ่งขึ้นเพื่อที่คุณจะได้เพลิดเพลิน stackoverflow.com/a/27030789/13
Chris Jester-Young

7
ที่จริงแล้วสิ่งนี้ทำให้ฉันต้องทำการวิจัยอย่างหนักในเรื่องนี้! ขอบคุณสำหรับความช่วยเหลือของคุณ!
Derek Adair

2
คำตอบของคุณทำให้เข้าใจผิดเล็กน้อย: toFixedเป็นฟังก์ชันการจัดรูปแบบซึ่งมีวัตถุประสงค์เพียงอย่างเดียวในการแปลงตัวเลขเป็นสตริงโดยทำการจัดรูปแบบโดยใช้จำนวนทศนิยมที่ระบุ เหตุผลที่ส่งคืนสตริงเนื่องจากควรส่งคืนสตริงและหากตั้งชื่อtoStringFixedแทน OP จะไม่แปลกใจที่ผลลัพธ์ ปัญหาเดียวที่นี่คือ OP คาดว่ามันจะทำงานเหมือนMath.roundโดยไม่ปรึกษา JS อ้างอิง
Groo

177

Number.prototype.toFixedเป็นฟังก์ชั่นที่ออกแบบมาเพื่อจัดรูปแบบตัวเลขก่อนพิมพ์ออกมา มันมาจากครอบครัวtoString, และtoExponentialtoPrecision

ในการปัดเศษตัวเลขคุณต้องทำดังนี้

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
คำตอบที่ดี! อย่างไรก็ตาม ... ฉันใช้จาวาสคริปต์มา 20 ปีแล้ว แต่ฉันไม่สามารถเข้าใจได้ว่าทำไมคุณถึงใช้สิ่งก่อสร้าง + (... ) ที่มีค่าส่งคืน ขอบคุณ @sam สำหรับการถูใน :) เนื่องจากฉันไม่เคยแก่เกินไปที่จะเรียนรู้โปรดอธิบายอย่างละเอียด :-)
HammerNL

1
แม้จะมีความเชื่อมั่น @HammerNL แซมก็ acutally ไม่ได้ทำอะไร :) มันเป็นเพียงการปฏิบัติ - มันทำให้ IDEs type Numberรับรู้ฟังก์ชั่นนี้เป็น สิ่งนั้นคือ+(anyValue)ส่งกลับตัวเลขเสมอ - เช่น +("45")ผลตอบแทน45, ผลตอบแทน+(new Number(42)) 42มันเหมือนกับฟังก์ชั่นการพิมพ์ที่แข็งแกร่ง ถ้าคุณทำนิสัยของมันคุณสามารถหลีกเลี่ยงข้อบกพร่องมาก :)
m93a

ทำไมสิ่งนี้ถึงไม่ถูกอบเข้าสู่จาวาสคริปต์หลัก: s
เว็บมาสเตอร์

2
resuit ของ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 ดังนั้นเพื่อเหตุผลด้านประสิทธิภาพ? สิ่งนี้มีผลกระทบที่เห็นได้ชัดเจนในประสิทธิภาพหรือไม่
Sebastianb

2
@ jczaplew เนื่องจาก Strings เป็น (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 ตำแหน่ง


ฉันรู้ว่าจาวาสคริปต์ไม่ใช่ภาษาที่ใช้ในการแสดงแต่โอกาสที่คุณจะได้รับประสิทธิภาพที่ดีขึ้นสำหรับการปัดเศษถ้าคุณใช้บางสิ่งเช่น: roundValue = Math.round (ค่า * 100) * 0.01


2

เพราะการใช้หลักแสดงตัวเลขหรือไม่ หากคุณต้องการปัดเศษตัวเลขให้ใช้Math.round()กับปัจจัย apropriate


แต่มันแสดงจำนวน NUMBERS ดังนั้นมันจะไม่ส่งกลับ "หมายเลข" หรือไม่
Derek Adair

3
@ ดีเร็ก: ในแบบที่'42'เป็นตัวเลขเท่านั้น ... ซึ่งไม่ใช่ เพียงเพราะสตริงเกิดขึ้นกับมีตัวเลขเท่านั้นไม่ได้ทำให้มันเป็นตัวเลข นี่ไม่ใช่ PHP :-P
Chris Jester-Young

ฮ่า ๆ. ไม่ใช่สตริงที่มีตัวเลข ... เป็นตัวเลขที่ส่งผ่านไปยังวิธีการ วิธีการใช้ตัวเลขและส่งกลับสตริง
Derek Adair

@DerekAdair ถูกต้อง แต่เบราว์เซอร์ไม่สามารถแสดงตัวเลขได้แสดงเป็นสตริงดังนั้นการแปลง
Nick M

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; }
Dino Liu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.