คลาส `Number` ในภาษา JavaScript
บทความนี้อธิบายเกี่ยวกับคลาส Number ในภาษา JavaScript
เราจะอธิบายลักษณะของ Number ข้อควรระวัง API ที่มีประโยชน์ และตัวอย่างใช้งานจริงอย่างละเอียดทีละขั้นตอน
YouTube Video
คลาส Number ในภาษา JavaScript
Number เป็นประเภทข้อมูลตัวเลขพื้นฐานในภาษา JavaScript และถูกแทนด้วยเลขทศนิยมความแม่นยำสองเท่า (IEEE-754, 64-bit)
พื้นฐาน: รูปแบบตัวเลขและการตรวจสอบประเภทข้อมูล
ในภาษา JavaScript ตัวเลขทั้งหมดจะแทนด้วยประเภทข้อมูลพื้นฐาน number
1// Primitive numbers and Number object
2const a = 42; // primitive number
3const b = 3.14; // primitive float
4const c = Number(10); // primitive via constructor call (function form)
5const d = new Number(10); // Number object (wrapper)
6
7console.log(typeof a); // "number"
8console.log(typeof d); // "object"
9console.log(c == d); // true (value coerces)
10console.log(c === d); // false (different types)
- โค้ดนี้แสดงให้เห็นถึงความแตกต่างระหว่าง
numberพื้นฐานและอ็อบเจกต์ห่อหุ้มNumberโดยปกติแล้วควรใช้ primitive แทนที่จะใช้ wrapper object
ค่าพิเศษ: NaN, Infinity และค่าคงที่
Number มีค่าพิเศษ (NaN, Infinity) และค่าคงที่ให้ใช้งาน
1// Special numeric values and constants
2console.log(Number.NaN); // NaN
3console.log(Number.POSITIVE_INFINITY); // Infinity
4console.log(Number.NEGATIVE_INFINITY); // -Infinity
5
6console.log(Number.MAX_VALUE); // largest positive representable
7console.log(Number.MIN_VALUE); // smallest positive representable (closest to 0)
8console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
9console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
10console.log(Number.EPSILON); // smallest difference ~2.220446049250313e-16
- จำนวนเต็มที่มากกว่าหรือเท่ากับ
MAX_SAFE_INTEGERอาจไม่สามารถแสดงค่าได้อย่างถูกต้อง หากต้องการความแม่นยำควรใช้BigIntEPSILONใช้สำหรับเปรียบเทียบเลขทศนิยม
การแปลงชนิดข้อมูลตัวเลข: Number(), parseInt, parseFloat และตัวดำเนินการ +
มีหลายวิธีในการแปลงสตริงเป็นตัวเลข ซึ่งแต่ละวิธีมีลักษณะการทำงานที่แตกต่างกัน
1// Converting strings to numbers
2console.log(Number("42")); // 42
3console.log(Number(" 3.14 ")); // 3.14
4console.log(+ "7"); // 7 (unary +)
5
6console.log(parseInt("42px")); // 42
7console.log(parseFloat("3.14abc"));// 3.14
8
9// Careful with parseInt and radix
10console.log(parseInt("08")); // 8
11console.log(parseInt("08", 10)); // 8 (explicit radix is safer)
Number()จะคืนค่าNaNหากสตริงไม่ใช่ตัวเลขล้วน ในขณะที่parseIntและparseFloatจะอ่านตัวเลขจากต้นสตริงจนกว่าจะเจออักขระที่ไม่ใช่ตัวเลข ควรระบุฐานตัวเลข (radix) อย่างชัดเจนเมื่อใช้parseIntเพื่อความปลอดภัย
การจัดการและตรวจสอบค่า NaN: isNaN และ Number.isNaN
NaN (Not-A-Number) มีความพิเศษที่ว่า NaN !== NaN ทั้งสองมีวิธีการตรวจสอบที่ต่างกัน isNaN แบบ global จะทำการแปลงชนิดข้อมูลและอาจให้ผลผิดพลาดได้ จึงแนะนำให้ใช้ Number.isNaN
1// NaN detection differences
2console.log(NaN === NaN); // false
3
4console.log(isNaN("foo")); // true -> because "foo" coerces to NaN
5console.log(Number.isNaN("foo")); // false -> "foo" is not the numeric NaN
6
7console.log(Number.isNaN(NaN)); // true
- ควรใช้
Number.isNaNในการตรวจสอบค่าตัวเลขและผลลัพธ์จากการคำนวณเพื่อเลี่ยงการแปลงชนิดข้อมูลโดยไม่จำเป็น
ข้อผิดพลาดของเลขทศนิยมและการเปรียบเทียบโดยใช้ Number.EPSILON
เนื่องจากมาตรฐาน IEEE-754 อาจเกิดข้อผิดพลาด เช่น 0.1 + 0.2 !== 0.3 สำหรับการเปรียบเทียบที่แม่นยำ มักใช้ค่าส่วนต่างและ Number.EPSILON
1// Floating point precision example and EPSILON comparison
2const sum = 0.1 + 0.2;
3console.log(sum === 0.3); // false
4
5function nearlyEqual(a, b, epsilon = Number.EPSILON) {
6 return Math.abs(a - b) <= epsilon * Math.max(1, Math.abs(a), Math.abs(b));
7}
8
9console.log(nearlyEqual(sum, 0.3)); // true
- หากต้องการเปรียบเทียบโดยยอมรับค่าความคลาดเคลื่อน ควรใช้ฟังก์ชันที่แข็งแรง เช่น
nearlyEqualที่ใช้ทั้งการเปรียบเทียบความต่างสัมบูรณ์และการปรับขนาด
การตรวจสอบจำนวนเต็มและจำนวนเต็มที่ปลอดภัย (isInteger, isSafeInteger)
มี API สำหรับตรวจสอบค่าว่าเป็นจำนวนเต็มหรือจำนวนเต็มที่อยู่ในช่วงที่ปลอดภัย
1// Integer and safe integer checks
2console.log(Number.isInteger(3)); // true
3console.log(Number.isInteger(3.0)); // true
4console.log(Number.isInteger(3.1)); // false
5
6console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)); // true
7console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false
- หากต้องการความแม่นยำสำหรับตัวเลขจำนวนเต็มขนาดใหญ่ ควรใช้
Number.isSafeIntegerในการตรวจสอบ และใช้BigIntหากเกินช่วงดังกล่าว
การแสดงผลและการจัดรูปแบบ: toFixed, toPrecision, toString
มีเมธอดสำหรับควบคุมการแสดงผลของค่าตัวเลข toFixed คืนค่าสตริงพร้อมทศนิยมตามที่กำหนด แต่ควรระวังเรื่องการปัดเศษ
1// Formatting numbers for display
2const x = 1.23456;
3console.log(x.toFixed(2)); // "1.23" (string)
4console.log(x.toPrecision(3)); // "1.23" (string with total significant digits)
5console.log((255).toString(16)); // "ff" (hexadecimal string)
toFixedคืนค่าสตริง ดังนั้นควรระวังเมื่อแปลงกลับมาเป็นตัวเลขเพื่อใช้คำนวณ
ข้อควรระวังเกี่ยวกับการต่อสตริงและตัวดำเนินการ +
ตัวดำเนินการ + ใช้ได้ทั้งการบวกเลขและการต่อสตริง อาจเกิดผลลัพธ์ที่ไม่คาดคิดได้ตามชนิดข้อมูล
1// Pitfall with + operator and type coercion
2console.log(1 + 2 + "px"); // "3px"
3console.log("px" + 1 + 2); // "px12"
4console.log(1 + "2" - 0); // 3 (string coerced to number for subtraction)
- เมื่อมีการผสมระหว่างสตริงกับตัวเลข ควรใช้
String(),Number()หรือ template literals อย่างชัดเจนเพื่อเลี่ยงการแปลงชนิดข้อมูลโดยอัตโนมัติ
กรณีการใช้งานขั้นสูง: Number.parseInt / Number.parseFloat, valueOf
Number.parseInt และ Number.parseFloat เป็น alias ของฟังก์ชัน global valueOf ใช้สำหรับดึงค่าพื้นฐานจาก object Number แต่โดยทั่วไปแทบไม่จำเป็นต้องใช้
1// Number.parseInt/parseFloat aliases and valueOf example
2console.log(Number.parseInt("100", 10)); // 100
3console.log(Number.parseFloat("3.14")); // 3.14
4
5const nObj = new Number(5);
6console.log(nObj.valueOf()); // 5
7console.log(nObj + 1); // 6 (object coerced to primitive)
- เมื่อใช้
Number.parseIntและNumber.parseFloatควรระวังเกี่ยวกับฐานตัวเลข (radix) และการตัดช่องว่างจาก input โดยทั่วไปควรเลี่ยงการใช้ wrapper object
ตัวอย่างยูทิลิตี้ฟังก์ชันสำหรับการตรวจสอบตัวเลข
ต่อไปนี้เป็นยูทิลิตี้ฟังก์ชันขนาดเล็กสำหรับตรวจสอบค่าต่างๆ ที่มักใช้กัน ช่วยให้ตรวจสอบค่าต่างๆ เช่น การ validate ข้อมูล input ได้ง่ายขึ้น
1// Small number utility functions
2function toNumberStrict(value) {
3 // Return a Number or throw for invalid numeric strings
4 const n = Number(value);
5 if (typeof value === "string" && value.trim() === "") {
6 throw new Error("Empty string is not a valid number");
7 }
8 if (Number.isNaN(n)) {
9 throw new Error(`Invalid number: ${value}`);
10 }
11 return n;
12}
13
14function almostEqual(a, b, eps = Number.EPSILON) {
15 // Robust relative comparison
16 return Math.abs(a - b) <= eps * Math.max(1, Math.abs(a), Math.abs(b));
17}- ฟังก์ชันเหล่านี้มีความยืดหยุ่นสูง สามารถใช้ซ้ำในการประมวลผลและเปรียบเทียบค่าข้อมูลได้ ฟังก์ชันที่โยน error เมื่อพบข้อมูลผิดปกติมีประโยชน์สำหรับการตรวจสอบข้อมูล
สรุปเรื่องประสิทธิภาพและแนวทางปฏิบัติที่ดี
ข้อแนะนำในการใช้งาน Number อย่างมีประสิทธิภาพ
- โดยพื้นฐานควรใช้ประเภทข้อมูล primitive
numberและหลีกเลี่ยงnew Number() - เลือกใช้
Number()(แบบเข้มงวด) หรือparseInt/parseFloat(ดึงตัวเลขจากสตริง) ให้เหมาะสมกับกรณีการใช้งานของคุณ - ใช้
Number.isNaNและNumber.isFiniteเพื่อการตรวจสอบค่าที่ปลอดภัย - สำหรับการเปรียบเทียบเลขทศนิยม ควรใช้
Number.EPSILONหรือสร้างฟังก์ชันเปรียบเทียบโดยเฉพาะ - หากต้องการความแม่นยำของจำนวนเต็ม ให้ใช้
Number.isSafeIntegerและหากเกินช่วง ควรใช้BigInt - คุณสามารถใช้
toFixedหรือtoPrecisionเพื่อปัดเศษสำหรับการแสดงผล แต่โปรดทราบว่าค่าที่คืนกลับมาจะเป็นสตริง
สรุป
Number เป็นชนิดข้อมูลพื้นฐานสำหรับตัวเลขทั้งหมดใน JavaScript รวมถึงจำนวนเต็ม ทศนิยม และค่าพิเศษต่าง ๆ (NaN และ Infinity) ควรระวังเรื่องการแปลงชนิดข้อมูลและข้อผิดพลาดของเลขทศนิยม และใช้เมธอด เช่น Number.isNaN และ Number.EPSILON ให้ถูกต้อง หากเกินช่วงจำนวนเต็มที่ปลอดภัย ให้ใช้ BigInt และใช้ toFixed หรือ toPrecision สำหรับการปัดเศษและแสดงผล
คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย