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

Nuttavut Thongjor

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

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

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

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

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

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

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

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

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

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

JavaScript
1class Article {
2 constructor(title, body) {
3 this.title = title
4 this.body = body
5
6 // อันนี้ private field นะ
7 // อย่าเถียงดิไม่เห็น _ รึ ไอ้หอยขม!
8 this._id = uuid.v4()
9 }
10}

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

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

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

JavaScript
1class Point {
2
3 #x;
4 #y;
5
6 constructor(x = 0, y = 0) {
7 #x = +x;
8 #y = +y;
9 }
10
11 get x() { return #x }
12 set x(value) { #x = +value }
13
14 get y() { return #y }
15 set y(value) { #y = +value }
16
17 equals(p) { return #x === p.#x && #y === p.#y }
18
19 toString() { return `Point<${ #x },${ #y }>` }
20
21}

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

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

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

JavaScript
1// ฟังก์ชันทำตัวอักษรแรกให้เป็นตัวพิมพ์ใหญ่
2const capitalize = (str) => str[0].toUpperCase() + str.substring(1)
3
4// แปลง - เป็นช่องว่าง
5const convertDashToSpace = (str) => str.replace(/-/g, ' ')
6
7// เราต้องการแปลงข้อความจาก
8// introduction-to-pipeline-operator
9// ให้เป็น Introduction to pipeline operator
10const slug = 'introduction-to-pipeline-operator'
11const slugWithoutDash = convertDashToSpace(slug)
12const sentenceCaseTitle = capitalize(slugWithoutDash)
13
14console.log(sentenceCaseTitle) // Introduction to pipeline operator

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

JavaScript
1const slug = 'introduction-to-pipeline-operator'
2
3capitalize(convertDashToSpace(slug))

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

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

Code
1slug |> convertDashToSpace |> capitalize

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

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

JavaScript
1let result = slug |> convertDashToSpace |> capitalize

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

Pattern Matching ก็มี

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

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

JavaScript
1const shape = { width: 10, height: 20 }
2
3function findArea() {
4 // ถ้ามี width และ height แสดงว่าเป็นสี่เหลียม
5 if (shape.width && shape.height) {
6 return shape.width * shape.height
7 }
8
9 // แต่ถ้ามี height และ base ต้องเป็นสามเหลี่ยมแน่ๆ
10 if (shape.height && shape.base) {
11 return 0.5 * shape.height * shape.base
12 }
13}

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

JavaScript
1const shape = { width: 10, height: 20 }
2
3function findArea(shape) {
4 return match(shape) {
5 { width, height }: shape.width * shape.height,
6 { height, base }: 0.5 * shape.height * shape.base,
7 else: { throw new Error('Unknown shape type') }
8 }
9}

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

Optional Chaining ก็มา

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

JavaScript
1const user = {
2 address: { street: 'XYZ' },
3}

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

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

JavaScript
1const street = user.address && user.address.street

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

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

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

JavaScript
1const 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

สารบัญ

สารบัญ

  • Private Fields ชาตินี้จะได้ใช้ไหม
  • Pipeline Operator เรียกต่อกัน ยาวไปยาวไป
  • Pattern Matching ก็มี
  • Optional Chaining ก็มา
  • เอกสารอ้างอิง