Babel Coder

อนาคตของ JavaScript จะมี Syntax อะไรเพิ่มบ้าง?

intermediate

ภาษามนุษย์ไม่ว่าจะภาษาไทยหรือภาษาอังกฤษเราไม่ได้เรียนรู้กันในคืนเดียว จะให้เปลี่ยนหรือเรียนภาษาที่สองยังยาก ไม่ต้องพูดถึงภาษาที่สามหรือสี่เลย แต่ถ้าได้ซักห้าภาษา… คุณก็คือ นาธาน แล้วครับ

ไม่ใช่สำหรับภาษาโปรแกรมที่ผุดกันเป็นดอกเห็ดเผาะในหน้าฝน ภาษาไหนที่เจ๋งหน่อยก็จะมีคนคอยสนับสนุนทำไลบรารี่ดีๆให้ นักพัฒนาก็จะคลานเข่าเข้าสวามิภักดิ์และหมอบกราบกลางสายฝน แล้วที่ยืนของภาษาที่ไม่เก๋าพอหละอยู่ตรงไหน?

เมื่อภาษาใหม่นั้นเจ๋งกว่า หากภาษาเก่ายังคงนั่งเล่นหมากเก็บอย่างสบายใจ โดยไม่พัฒนาโครงสร้างทางภาษาให้ดีขึ้น ซักวันก็คงไม่ต่างกับหลุมดำไกลโพ้น ที่ไม่มีใครมองเห็น ไม่มีใครสนใจ แม้ตัวเองจะมีแรงดึงดูดมากเพียงใด ก็มิอาจฉุนรั้งใครได้

JavaScript เป็นหนึ่งในภาษาเก่าแก่จนหงอกหลุดไปหลายเส้นละ ที่พัฒนาตามมาตรฐานของ ECMAScript โดยได้รับการพัฒนาเรื่อยมาจนก้าวกระโดดอย่างสูงในมาตรฐานของ ES2015 และยังคงได้รับการพัฒนาเรื่อยมาจนถึงปี 2017 (ES2017) ในปัจจุบัน

เพื่อไม่ให้ JavaScript ต้องถูกทอดทิ้ง TC39 ผู้แลดูและดูแลมาตรฐานของ ECMAScript จึงต้องขับเคลื่อนให้มาตรฐานนี้เดินหน้าต่อไปในฐานะคู่แข่งที่ทัดเทียมกับภาษาแห่งโลกสมัยใหม่

บทความนี้ผมจะนำเสนอมาตรฐานทางภาษาใหม่ๆของ ECMAScript ที่อาจจะถูกเพิ่มในอนาคต การที่เราได้รู้ฟีเจอร์เหล่านี้ล่วงหน้านอกจากจะเพิ่มความ Geek ให้ไปอวดเบ่งสาวได้แล้ว มันยังทำให้โลกทรรศน์ของเรากว้างขึ้นอีกด้วย

สำหรับเพื่อนๆที่สนใจกระบวนการพัฒนา ECMAScript ว่ากว่าจะออกมาเป็นมาตรฐานได้นั้นต้องบุกป่าฝ่าดงยังไงบ้าง เสพลิงก์นี้ซิ รอไร!

พูดกันมาหลายย่อหน้าแล้ว ไปดูกันดีกว่าว่าไวยากรณ์ที่ “อาจ” จะถูกเพิ่มเข้ามานี้ มีอะไรน่าสนใจบ้าง

สารบัญ

Private Fields ชาตินี้จะได้ใช้ไหม

แม้ ES2015 จะมาพร้อมกับความสามารถของคลาส แต่ private fields ก็เป็นแค่อสุจิตัวจิ๋วที่หาไข่ไม่เจอซักที โปรแกรมเมอร์หลายคนจึงเลือก “มโน” ด้วยการใส่ _ นำหน้าชื่อฟิลด์ พร้อมทั้งชักชวนให้ผองเพื่อน “เออออห่อหมก” ว่านี่คือ private fields นะเออ

class Article {
  constructor(title, body) {
    this.title = title
    this.body = body
    
    // อันนี้ private field นะ 
    // อย่าเถียงดิไม่เห็น _ รึ ไอ้หอยขม!
    this._id = uuid.v4()
  }
}

รสชาติมันก็จะแปลกๆหน่อย แต่สารภาพมาเถอะว่าคุณก็ใช้~

เรามีความพยายามที่จะซ่อนข้อมูลกันมานานแล้วครับ วิธีการก็มีทั้งดีบ้างแย่บ้างคละเข่งกันไป หากเพื่อนๆคนไหนสนใจในรายละเอียด วาปอยู่นี่กับบทความ Private Fields ใน JavaScript: จาก ES5 สู่ ECMAScript Proposal

เพื่อหยุดความสิ้นหวังของโลกใบนี้ ภายใต้การกำกับของ ECMAScript จึงมีการเสนอมาตรฐานของการสร้าง private fields ด้วยการใช้เครื่องหมาย # นำหน้าชื่อ

class Point {

    #x;
    #y;

    constructor(x = 0, y = 0) {
        #x = +x;
        #y = +y;
    }

    get x() { return #x }
    set x(value) { #x = +value }

    get y() { return #y }
    set y(value) { #y = +value }

    equals(p) { return #x === p.#x && #y === p.#y }

    toString() { return `Point<${ #x },${ #y }>` }

}

ก็กิ๊บเก๋ไปอีกแบบนะ แต่ก็ยังไม่วายที่จะมีกระทาชายผู้สงสัยว่าทำไมต้อง # ใช้คำว่า private แบบภาษาอื่นมิได้ฤา หรือจะใช้ @ แบบภาษา Ruby งี้ไม่ได้หรอแว๊ ส่วนคำตอบของทีมงานจะเป็นเช่นไร เสพเอาเองที่นี่ครับ

Pipeline Operator เรียกต่อกัน ยาวไปยาวไป

เหนื่อยไหมกับการส่งค่าข้ามไปมาระหว่างฟังก์ชันหลายๆรอบ

// ฟังก์ชันทำตัวอักษรแรกให้เป็นตัวพิมพ์ใหญ่
const capitalize = str => str[0].toUpperCase() + str.substring(1)

// แปลง - เป็นช่องว่าง
const convertDashToSpace = str => str.replace(/-/g, ' ')

// เราต้องการแปลงข้อความจาก
// introduction-to-pipeline-operator 
// ให้เป็น Introduction to pipeline operator
const slug = 'introduction-to-pipeline-operator'
const slugWithoutDash = convertDashToSpace(slug)
const sentenceCaseTitle = capitalize(slugWithoutDash)

console.log(sentenceCaseTitle) // Introduction to pipeline operator

ลากเลือดมาก กว่าจะได้ผลลัพธ์ต้องตรากตรำประกาศตัวแปรมารองรับมากมาย งั้นเอาใหม่

const slug = 'introduction-to-pipeline-operator'

capitalize(convertDashToSpace(slug))

ด้วยพลานุภาพของการประกอบฟังก์ชันทำให้เราไม่ต้องประกาศตัวแปรคั่นกลาง แต่กระนั้นก็แลกมาด้วยโค้ดที่อ่านยากขึ้น

ภาษาตระกูล functional หลายภาษาลอกเลียนแบบการใช้งาน pipe มาจาก UNIX เช่นภาษา Elixir การใช้งาน pipe จะทำให้ผลลัพธ์ของการทำงานก่อนหน้าส่งไปเป็นพารามิเตอร์ตัวแรกของฟังก์ชันถัดไป

slug |> convertDashToSpace |> capitalize

คุณแพะภูเขา เพียงการใช้งาน pipe operator (|>) ก็ทำให้โค้ดของเราอ่านง่ายขึ้น เราทราบได้ทันทีว่าค่าตั้งต้นของเราอยู่ในตัวแปร slug จากนั้นจึงส่งเข้าไปเป็นพารามิเตอร์ของ convertDashToSpace ผลลัพธ์จากการทำงานก็ส่งต่อไปให้ capitalize ดีงามแบบนี้ ต่อให้ไม่มีของแถมก็ซื้อเลย!

ฟีเจอร์ทางภาษาดีๆแบบนี้ มีหรือ ES จะไม่อยากคัดลอก ด้วยวิญญาณความเป็นจีนเซินเจิ้นในตัว ทีมงาน TC39 ผู้พัฒนา ECMAScript จึงก็อบปี้และแปะให้ใช้งานได้ดังนี้

let result = slug
  |> convertDashToSpace
  |> capitalize

ไม่ต้องสืบ โค้ดเดียวกันนั่นละ!

Pattern Matching ก็มี

ภาษาตระกูล functional (อีกละ) ก็มีคอนเซ็ปต์ของ Pattern Matching เพราะความเซินเจิ้นในกระแสเลือดนั้นข้นกว่าน้ำ TC39 จึงมีแนวคิดที่จะเพิ่มสิ่งนี้ให้กับตัวภาษา

สมมติเรามีรูปร่าง (shape) อันนึง รูปนี้อาจเป็นสามเหลี่ยมก็ได้ เป็นสี่เหลี่ยมเหมือนหน้าอดีตท่านผู้นำก็ย่อมได้ เราจึงต้องมีการตรวจสอบอ็อบเจ็กต์รูปร่างของเราซะหน่อยว่ามีคุณสมบัติเป็นเช่นไร ก่อนทำการหาพื้นที่ต่อไป

const shape = { width: 10, height: 20 }

function findArea() {
  // ถ้ามี width และ height แสดงว่าเป็นสี่เหลียม
  if(shape.width && shape.height) {
    return shape.width * shape.height
  }
  
  // แต่ถ้ามี height และ base ต้องเป็นสามเหลี่ยมแน่ๆ
  if(shape.height && shape.base) {
    return 0.5 * shape.height * shape.base
  }
}

ทว่า Pattern Matching ทำให้เราเข้าคู่อ็อบเจ็กต์เหมือนที่เราเข้าขากับคู่เดทได้อย่างดี โค้ดของเราจึงกรุบกรอบได้มากขึ้นโดยไม่ต้องผสมบอแร็กซ์เลยละ

const shape = { width: 10, height: 20 }

function findArea(shape) {
  return match(shape) {
    { width, height }: shape.width * shape.height,
    { height, base }: 0.5 * shape.height * shape.base,
    else: { throw new Error('Unknown shape type') }
  }
}

จงดีใจซะ ตอนนี้ Pattern Matching อยู่ใน Stage-0 เป็นที่เรียบร้อยล้าวว

Optional Chaining ก็มา

จินตนาการถึงการแสดงผลชื่อถนนของเราจากอ็อบเจ็กต์ต่อไปนี้

const user = {
  address: { street: 'XYZ' }
}

พระเจ้าก็ไม่รู้ บางทีในอ็อบเจ็กต์ของ user อาจไม่มี address อยู่ก็ได้ แม้จะมี address ก็ไม่มีหลักประกันว่า street จะมีอยู่เช่นกัน

เพื่อให้เราแสดงผล street โดยไม่เกิดข้อผิดพลาด เราจึงต้องตรวจสอบเสียก่อนว่าภายใต้ user นั้นมี address ดังนี้

const street = user.address && user.address.street

ในภาษาอื่นๆเช่น Ruby เรามีสิ่งที่เรียกว่าเป็น Safe navigation operator ที่จะช่วยให้โค้ดอ่านง่ายขึ้น

# หาก user ไม่มี address ก็จะคืน nil ไม่พ่น error
# หาก address ไม่มี street ก็จะคืน nil ไม่พ่น error
const street = user&.address&.street

ด้วยมาตรฐานที่เรากำลังพูดถึง ECMAScript จะมีตัวดำเนินการ ?. ที่เรียกว่า Optional Chaining operator เพื่อใช้จัดการตามสิ่งที่เราพูดถึงกันในหัวข้อนี้

const street = user.address?.street

คุ้นๆไหม? มันคือ Safe navigation operator ใน Angular 2+ ยังไงละ อยากจะขรรม~

สำหรับมาตรฐานนี้ ขณะที่เขียนบทความก็อยู่ใน Stage-1 เป็นที่เรียบร้อยแล้วจ้า

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

TC39. ECMAScript Private Fields. Retrieved August, 8, 2017, from https://github.com/tc39/proposal-private-fields

TC39. ESNext Proposal: The Pipeline Operator. Retrieved August, 8, 2017, from https://github.com/tc39/proposal-pipeline-operator

TC39. ECMAScript Pattern Matching Syntax. Retrieved August, 8, 2017, from https://github.com/tc39/proposal-pattern-matching

TC39. Optional Chaining for JavaScript. Retrieved August, 8, 2017, from https://github.com/tc39/proposal-optional-chaining


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


Saran3 เดือนที่ผ่านมา

ขอบคุณสำหรับบทความดีๆนะครับ แต่ขอติเล็กน้อย

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

เจอฝรั่งเอา Trump มาผสมในบทความ จิ๊กกัดคนอื่น มาอ่านไทยก็ยังไม่พ้นการเมืองกับการจิ๊กกัด


Non Hasitabhan3 เดือนที่ผ่านมา

ชอบหลายๆ syntax ใน coffeescript จนตอนนี้ javascript ก็ตอบโจทย์แล้ว~