Babel Coder

void operator อีกหนึ่งตัวดำเนินการใน JavaScript ที่ใช้แทน undefined

beginner

มีเพื่อนๆคนไหนเคยใช้ Backbone.js ไหมครับ? โค๊ดแบบนี้อาจผ่านตาเพื่อนๆมาบ้างเช่น if (context === void 0) return func; โดยเฉพาะอย่างยิ่งในตัวของ Backbone.js เองก็จะเจอโค๊ดทำนองนี้ ทำนองนี้ที่ว่าหมายถึงการใช้ void 0 ว่าแต่แล้ว void ใน JavaScript เนี่ยมันคืออะไรกันเหมือน void ในภาษาตระกูล C หรือเปล่านะ?

สารบัญ

เชื่อไหมว่า undefined ไม่ใช่คำสงวนในภาษา!

undefined ที่เราคุ้นเคยกันในความหมายว่า ไม่มีค่า นั้นไม่ใช่ reserved word ครับ เมื่อมันไม่เป็นคำสงวนแล้วเราจึงหยิบ undefined มาตั้งเป็นชื่อตัวแปรได้ แท้จริงแล้ว undefined ที่เราใช้กันอยู่นี้เป็นเพียง property ตัวหนึ่งของ Global Object ในภาษา JavaScript แค่นั้นเอง

เรื่องมันเกิดจากเราสามารถใช้ undefined เป็นชื่อตัวแปรได้ ดังนั้นแล้วถ้าใครเผลอไปกำหนดค่าให้ undefined ใหม่อีกรอบโค๊ดที่เล่นกับ undefined ก็จะพังพินาศไปทันที

// ES version < 5
undefined = 5
var a

if(a === undefined) {
  // แทนที่จะพิมพ์ undefined ออกมา
  // โค๊ดนี้กลับไม่ทำอะไรเพราะตอนนี้ undefined ของเรามีค่าเป็น 5
  // แทนที่จะหมายถึงการไม่มีค่าแบบเราตั้งใจไว้
  console.log('undefined')
}

เมื่อเป็นเช่นนี้เราจึงเชื่อมั่นและศรัทธาใน undefined ไม่ได้ มีตัวดำเนินการหนึ่งที่เป็นทั้ง reserved word และให้ค่าออกมาเป็น undefined นั่นคือ void เราจึงสามารถใช้ void ในความหมายของ undefined ได้ ต่อไปนี้จงถือว่า void คือพระเจ้าสูงสุดได้เลยเพราะเราเขียนค่าทับ void ไม่ได้ ก็นะมันเป็นคำสงวนหนิ

undefined = 5
var a
if(a === void 0) {
  console.log('undefined')
}

void นั้นต้องตามด้วย expression เราจึงต้องใส่อะไรซักอย่างต่อท้าย ในที่นี้ผมเลือกใส่ศูนย์เพราะมันสั้นและดูมีรสนิยมหรูหรากว่าการใช้เลขอื่น ทั้งนี้เพื่อนๆจะใส่เลขอื่นหรืออักษรอะไรแทนศูนย์ก็ได้ครับ ผลลัพธ์ไม่แตกต่างกัน

ES5 กับ undefined

Backbone.js เป็นเฟรมเวิร์คที่เกิดขึ้นมายาวนานมากแล้ว และเพื่อป้องกันข้อผิดพลาดจากการเขียนทับค่าของ undefined ตัว Backbone.js เองจึงเลือกใช้ void 0 เป็นตัวเทียบค่าว่างแทน undefined

การมาถึงของ ES5 ทำให้โลกของ undefined เปลี่ยนไป กล่าวคือตอนนี้ undefined ของเราเป็นเพียง property ที่อ่านได้อย่างเดียวแล้วครับ เราจะเปลี่ยนค่าแบบเก่าไม่ได้แล้วแต่ทั้งนี้ undefined ก็ยังคงไม่ใช่ reserved word เช่นเดิมครับ

Cannot assign to read only property 'undefined' of object '#<Window>'

ถ้าเป็นเช่นนี้ void ก็ไม่มีความหมายอะไรแล้วซิ ก็ ES5 ทำให้ชีวิตเราง่ายขึ้นด้วยการไม่อนุญาตให้เปลี่ยนค่าของ undefined แล้ว?

เพราะ void ยังมีประโยชน์อยู่มันจึงคงอยู่อย่างคงกระพันในภาษา JavaScript ต่อไป…

void กับ JavaScript URIs

ปกติแล้วใน href ของแท็ก a เราชอบใส่ # กันใช่ไหมครับถ้าไม่ต้องการให้กดลิงก์แล้ววิ่งไปที่ URL ไหน

<a href='#'>Click me เลยซิ</a>

ทั้งนี้การใส่ # ก็ยังมีข้อเสียคือเพจของเราจะวิ่งไปข้างบนสุด แน่นอนว่าเราไม่ต้องการแบบนี้แน่เราจึงต้องหลีกเลี่ยงไปใช้วิธีอื่น ครั้นจะใส่ event.preventDefault ใน onClick ก็ดูยาวไปซึ่งมันขัดกับสกิลขี้เกียจพิมพ์ของโปรแกรมเมอร์ยิ่งนัก

href สามารถใส่ JavaScript URI ได้ครับ มันคือข้อความ javascript: URI โดยเมื่อเรากดลิงก์แล้วหน้าเพจของเราจะแทนที่ด้วยสิ่งที่ได้จากการประมวลผล URI ที่เราใส่ไปเช่น

<!-- เมื่อคลิกแล้วเพจของเราจะกลายเป็นข้อความ Babel Coder แทน -->
<a href="javascript: 'Babel Coder'">Click me เลยซิ</a>

แล้วถ้าเราใส่ void 0 แทนหละที่มีความหมายว่า undefined ไง? มันก็จะไม่มีอะไรเกิดขึ้นไงครับ ทั้งหน้าเพจไม่เลื่อนขึ้นไปบนสุดด้วยและไม่มีการทับข้อความใดๆลงหน้าเพจของเราด้วยเช่นกัน

<a href='javascript:void 0'>Click me เลยซิ</a>

<!-- มีค่าเท่ากัน แต่วงเล็บทำให้ดูดีงามพระรามแปด -->
<a href='javascript:void(0)'>Click me เลยซิ</a>

void กับ Immediately Invoked Function Expressions (IIFE)

IIFE เป็นเทคนิคเก่าในการปกป้องให้ตัวแปรของเรามองเห็นได้ในขอบเขตจำกัด หรือพูดง่ายๆก็คือสามารถใช้มันเพื่อสร้างโมดูลได้

function print() {
  console.log('print')
}

const message = 'abc'

const iife = (
  function(message) {
    return {
      // print ตัวนี้ไม่สัมพันธ์หรือเขียนทับกับ print ตัวนอก
      print() {
        // message ตัวนี้ไม่เกี่ยวข้องกับ message ข้างนอก
        console.log(message)
      }
    }
  }
)('IIFE')

print() // print
iife.print() // IIFE

เพื่อนๆที่งงหรือไม่เข้าใจว่า IIFE คืออะไรแนะนำให้อ่านเพิ่มได้จาก 7 เรื่องพื้นฐานชวนสับสนใน JavaScript สำหรับผู้เริ่มต้น ในหัวข้อ Closure ครับ

กลับมาเข้าเรื่อง void กันครับ ปกติเวลาเราประกาศฟังก์ชันมันก็คือการประกาศชื่อของฟังก์ชันไปด้วยพร้อมกัน เราจึงสามารถเรียกชื่อของฟังก์ชันนั้นได้

// ส่วนนี้คือส่วนประกาศฟังก์ชัน เราจึงเรียกใช้ abc ได้
// เพราะมีชื่อ abc จากส่วนประกาศนี้ให้อ้างถึง
function abc() {
  console.log('abc')
}

abc()

แต่ทีนี้ถ้าเราใส่ void เข้าไปข้างหน้าส่วนประกาศฟังก์ชัน มันจะเปลี่ยนส่วนประกาศนี้ให้กลายเป็นนิพจน์ (expression) แทน

// เราไม่ได้ประกาศชื่อ abc แล้ว
// จึงไม่สามารถเข้าถึงชื่อ abc ได้
void function abc() {
  console.log('abc')
}

abc() // abc is not defined

เมื่อเราเปลี่ยนประโยคประกาศฟังก์ชันให้เป็นนิพจน์แล้วจึงไม่มีความจำเป็นต้องใช้วงเล็บเพื่อห่อฟังก์ชันใน IIFE อีกต่อไป

(function(message) {
  console.log(message)
})('IIFE')

// มีค่าเท่ากัน
void function(message) {
  console.log(message)
}('IIFE')

เพื่อนๆคงได้คำตอบกับแล้วนะครับว่า void ใน JavaScript เหมือนหรือต่างจากภาษาตระกูล C อย่างไร เรื่องของ void นั้นพูดไปแล้วก็ไม่ค่อยได้ใช้กันหรอกครับเว้น javascript:void(0) ไว้ตัวนึงแล้วกัน

เอกสารอ้างอิง

MDN. void operator. Retrieved June, 21, 2016, from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void

What does void 0 mean?. Retrieved June, 21, 2016, from http://stackoverflow.com/questions/7452341/what-does-void-0-mean


แสดงความคิดเห็นของคุณ


No any discussions