ตัวดำเนินการระดับบิต ในภาษา JavaScript

ในบทนี้ เป็นเนื้อหาของตัวดำเนินการระดับบิตในภาษา JavaScript คุณจะได้เรียนรู้ว่าตัวดำเนินการระดับบิตคืออะไร และมันถูกนำไปใช้อย่างไรในการเขียนโปรแกรม

ตัวดำเนินการระดับบิต

ตัวดำเนินการระดับบิต (Bitwise operators) คือตัวดำเนินการที่ดำเนินการในระบิตของข้อมูล โดยทั่วไปแล้วตัวดำเนินการระดับบิตมักใช้ในการเขียนโปรแกรมระดับต่ำ (Low level) เนื่องจากมันมีการทำงานที่เรียบง่ายและรวดเร็วในการคำนวณและเปรียบเทียบค่า เพราะการทำงานนั้นเกิดขึ้นกับแต่ละบิตในหน่วยความจำโดยตรง

ในบทนี้ เราจะใช้ตัวตัวดำเนินการระดับบิตกับตัวเลขจำนวนเต็มเพื่อความง่าย ในการเขียนคอมพิวเตอร์นั้น ข้อมูลจะถูกเก็บในหน่วยความจำในรูปแบบของเลขฐานสอง (Binary form) นี่เป็นตารางแสดงความสัมพันธ์ค่าของตัวเลขจาก 0 ถึง 15 กับค่าที่เก็บในหน่วยความจำ

DECIMAL BINARY  DECIMAL BINARY
0       0000    8       1000
1       0001    9       1001
2       0010    10      1010
3       0011    11      1011
4       0100    12      1100
5       0101    13      1101
6       0110    14      1110
7       0111    15      1111

ในตัวอย่าง เป็นการแสดงค่าในรูปแบบเลขฐานสองของตัวเลข 0 ถึง 15 ในทางทฤษฎีแล้ว ภาษา JavaScript นั้นเก็บตัวเลขโดยใช้หน่วยความจำ 64 บิต นั่นหมายความว่า 5 ถูกเก็บในหน่วยความจำเป็น ...0101 โดยที่ ... หน้าตัวเลขนั้นประกอบไปด้วย 0 อีก 60 ตัว ในกรณีนี้เราแสดงเพียงบิตทางด้านขวาสุดเพื่อความเรียบง่าย

ต่อไปมาดูกันว่าตัวดำเนินการระดับบิตนั้นมีอะไรบ้าง และนี่เป็นตารางของตัวดำเนินการระดับบิตทั้งหมดในภาษา JavaScript

สัญลักษณ์ ตัวดำเนินการ ตัวอย่าง
& BIT AND a & b
| BIT OR a | b
^ BIT XOR a ^ b
~ BIT INVERT ~a
<< BIT SHIFT LEFT a << n
>> BIT SHIFT RIGHT a >> n

ตัวดำเนินการระบิตนั้นทำงานคล้ายกับตัวดำเนินการตรรกศาสตร์ AND OR และ NOT แต่แทนที่จะจัดการกับค่า true และ false มันจะเป็นการทำงานกับแต่ละบิต 1 และ 0 ของข้อมูลแทน และนี่เป็นการทำงานของตัวดำเนินการแต่ละประเภท

  • BIT AND: ได้ผลลัพธ์เป็น 1 ถ้าค่าบิตทั้งสองเป็น 1 ไม่เช่นนั้นได้ผลลัพธ์เป็น 0
  • BIT OR: ได้ผลลัพธ์เป็น 1 ถ้าค่าบิตอย่างน้อยหนึ่งบิตเป็น 1 ไม่เช่นนั้นได้ผลลัพธ์เป็น 0
  • BIT XOR: ได้ผลลัพธ์เป็น 1 ถ้าค่าบิตทั้งสองแตกต่างกัน ไม่เช่นนั้นได้ผลลัพธ์เป็น 0
  • BIT INVERT: กลับบิตจาก 1 เป็น 0 และกลับบิตจาก 0 เป็น 1
  • BIT SHIFT LEFT: เลื่อนบิตไปทางซ้าย n ตำแหน่ง และเติมบิต 0 เข้ามาทางขวาเป็นจำนวน n บิต
  • BIT SHIFT RIGHT: เลื่อนบิตไปทางขวา n ตำแหน่ง บิตทางขวาสุด n ตำแหน่งจะถูกนำออกไป และเติมบิต 0 เข้ามาทางซ้าย

หลังจากที่ได้รู้ว่าตัวดำเนินแต่ละแบบนั้นทำงานอย่างไร ต่อไปมาดูตัวอย่างการใช้งาน เรามาเริ่มกับตัวดำเนินการ BIT AND และ BIT OR กันก่อน

console.log(3 & 10);    // 2
console.log(3 | 10);    // 11

ในตัวอย่าง เป็นการใช้งานตัวดำเนินการระดับบิตเพื่อจัดการกับค่าบิตของตัวเลขจำนวนเต็ม เนื่องจากในหน่วยความจำ (ที่แสดงในตารางก่อนหน้า) ค่าของ 3 และ 10 ถูกเก็บในรูปแบบของเลขฐานสองเป็น 0011 และ 1010 ตามลำดับ ดังนั้น การทำงานของตัวดำเนินการ BIT AND และ BIT OR สามารถแสดงให้เห็นเป็นรูปภาพได้ดังนี้

BIT AND     
0011  (3)
1010  (10)
====
0010  (2)

ตัวดำเนินการจะทำงานทีละคู่ของบิตโดยเริ่มจากบิตทางด้านขวาสุดของ 3 และ 10 ไปยังบิตที่อยู่ทางด้านซ้าย

ในการทำงานของ BIT AND จะเห็นว่าทั้งบิตของ 3 และ 10 ในตำแหน่งที่สองจากทางด้านซ้ายมีค่าเป็น 1 ทั้งคู่ ดังนั้นบิตผลลัพธ์จึงมีค่าเป็น 1 และบิตในตำแหน่งอื่นๆ มีค่าผลลัพธ์เป็น 0 ดังนั้นผลลัพธ์ที่ได้จากการดำเนินการคือ 0010 ซึ่งมีค่าเท่ากับ 2 ในฐานสิบ

BIT OR
0011  (3)
1010  (10)
====
1011  (11)

ในการทำงานของ BIT OR ถ้าหากค่าบิตอย่างน้อยหนึ่งบิตเป็น 1 บิตผลลัพธ์จะมีค่าเป็น 1 นั่นทำให้มีเพียงบิตตำแหน่งที่สองจากทางซ้ายเท่านั้นที่ได้บิตผลลัพธ์เป็น 0 ส่วนตำแหน่งอื่นจะได้บิตผลลัพธ์เป็น 1 ดังนั้นผลลัพธ์ที่ได้จากการดำเนินการคือ 1011 ซึ่งมีค่าเท่ากับ 11 ในฐานสิบ

ตัวดำเนินการ BIT NOT นั้นทำงานกับค่าเพียงหนึ่งค่าเท่านั้น นี่เป็นตัวอย่าง

console.log(~7);    // -8

เมื่อเราใช้งานตัวดำเนินการ BIT NOT มันได้ทำการกลับค่าบิตของเครื่องหมายด้วย ซึ่งตัวเลขในภาษา JavaScript นั้นมีบิตสำหรับเก็บว่าตัวเลขเป็นจำนวนบวกหรือลบ โดย 0 หมายถึงค่าบวก และ 1 หมายถึงค่าลบ

SIGN    DIGIT
0       0111
============
1       1000

ดังนั้นตัวดำเนินการ BIT NOT ทำงานในสองส่วนคือกลับบิตที่เก็บค่าของตัวเลขจาก 0111 เป็น 1000 และกลับบิตเครื่องหมายจาก 0 เป็น 1 ดังนั้นผลลัพธ์ที่ได้จึงเท่ากับ -8 นั่นเอง

ตัวอย่างถัดมาเป็นการใช้ตัวดำเนินการ BIT SHIFT LEFT และ BIT SHIFT RIGHT สำหรับเลื่อนบิตไปทางซ้ายและทางขวาตามลำดับ นี่เป็นตัวอย่าง

console.log(8 >> 2);    // 2
console.log(5 << 2);    // 20 

ในตัวอย่าง เราได้เลื่อนบิตไปทางซ้ายสองตำแหน่ง และเลื่อนไปทางขวาสองตำแหน่ง ซึ่งสามารถแสดงการทำงานแบบรูปภาพได้ดังนี้

BIT SHIFT RIGHT
1000
>>>> by 2
0010

ในการเลื่อนบิต 1000 ไปทางขวาสองตำแหน่ง จะทำให้บิตทางด้านขวาสุดสองบิตถูกนำออกไป และบิต 0 สองบิตเลื่อนเข้ามาแทนจากทางซ้าย ทำให้ได้บิตผลลัพธ์เป็น 0010 ซึ่งมีค่าเท่ากับ 2 ในฐานสิบ

BIT SHIFT LEFT
 0101
 <<<< by 2
10100 

สำหรับการเลื่อนบิต 0101 ไปทางซ้ายสองตำแหน่ง จะทำให้มีบิต 0 เพิ่มเข้ามาจากทางด้านขวาสองตำแหน่ง นั้นทำให้ได้บิตผลลัพธ์เป็น 10100 ซึ่งมีค่าเท่ากับ 20 ในฐานสิบ

สังเกตว่าในการเลื่อนบิตไปทางขวาหนึ่งตำแหน่งจะทำให้ค่าลดลงครึ่งหนึ่ง และการเลื่อนบิตไปทางซ้ายหนึ่งตำแหน่งจะทำให้ค่าเพิ่มขึ้นสองเท่า

การแสดงตัวเลขในรูปแบบเลขฐานสอง

เมื่อคุณต้องการทำงานกับตัวเลขในรูปแบบเลขฐานสอง ยกตัวอย่างเช่น ต้องการทราบว่าตัวเลขแสดงในรูปแบบของฐานสองเป็นอย่างไร คุณสามารถให้เมธอด toString เพื่อแปลงตัวเลขให้เป็น String ในเลขฐานสองได้ โดยกำหนดพารามิเตอร์ที่สองเป็น 2 นี่เป็นตัวอย่าง

console.log((3).toString(2));   // 11
console.log((10).toString(2));  // 1010
console.log((0.5).toString(2)); // 0.5
console.log((2.8).toString(2)); // 10.110011...

และในทางกลับกัน ถ้าหากคุณมี String ของตัวเลขในรูปแบบเลขฐานสองและต้องการแปลงเป็นตัวเลขจำนวนเต็ม คุณสามารถใช้ฟังก์ชัน parseInt โดยใส่พารามิเตอร์ตัวที่สองเป็น 2 เพื่อแปลงจากเลขฐานสองเป็นจำนวนเต็มได้ นี่เป็นตัวอย่าง

let a = parseInt("11", 2);
let b = parseInt("1010", 2);
console.log(a);     // 3
console.log(b);     // 10

และนี่เป็นผลลัพธ์การทำงานของตัวอย่างการใช้ตัวดำเนินการระดับบิตของเรา โดยปกติแล้ว ฟังก์ชัน console.log จะแสดงข้อมูลเป็นเลขฐานสิบเสมอ และเพื่อดูมันในรูปแบบของเลขฐานสอง เราใช้เมธอด toString ในการแปลงก่อนการแสดงผล

console.log((3 & 10).toString(2));    // 10
console.log((3 | 10).toString(2));    // 1011
console.log((~7).toString(2));        // -1000
console.log((8 >> 2).toString(2));    // 10
console.log((5 << 2).toString(2));    // 10100 

และนี่เป็นเพียงเทคนิคการใช้งานเมธอดเมื่อเราต้องทำงานกับตัวเลขและต้องการใช้มันในรูปแบบของเลขฐานสองเท่านั้น ในความเป็นจริงแล้วเมธอด toString และ parseInt สามารถทำงานกับตัวเลขฐานอื่นๆ ได้ เช่น ฐานแปด หรือฐานสิบหก เป็นต้น นี่เป็นรูปแบบการใช้งานของฟังก์ชันทั้งสอง

// Convert number to base n string
Number.toString(n);
// Parse string from base n to number (base 10)
Number.parseInt(str, n);

ในบทนี้ คุณได้เรียนรู้เกี่ยวกับตัวดำเนินการระดับบิตในภาษา JavaScript ซึ่งเป็นตัวดำเนินการที่เราสามารถใช้มันจัดการกับบิตของข้อมูลได้โดยตรง นอกจากนี้ เรายังแนะนำเทคนิคการใช้งานเมธอด toString และ parseInt สำหรับแปลงตัวเลขไปและกลับระหว่างฐาน 10 และเลขฐานอื่นๆ