คลาส `Number` ในภาษา JavaScript

คลาส `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 อาจไม่สามารถแสดงค่าได้อย่างถูกต้อง หากต้องการความแม่นยำควรใช้ BigInt EPSILON ใช้สำหรับเปรียบเทียบเลขทศนิยม

การแปลงชนิดข้อมูลตัวเลข: 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 ด้วย

YouTube Video