อนาคตของ JavaScript จะมี Syntax อะไรเพิ่มบ้าง?
ภาษามนุษย์ไม่ว่าจะภาษาไทยหรือภาษาอังกฤษเราไม่ได้เรียนรู้กันในคืนเดียว จะให้เปลี่ยนหรือเรียนภาษาที่สองยังยาก ไม่ต้องพูดถึงภาษาที่สามหรือสี่เลย แต่ถ้าได้ซักห้าภาษา... คุณก็คือ นาธาน แล้วครับ
ไม่ใช่สำหรับภาษาโปรแกรมที่ผุดกันเป็นดอกเห็ดเผาะในหน้าฝน ภาษาไหนที่เจ๋งหน่อยก็จะมีคนคอยสนับสนุนทำไลบรารี่ดีๆให้ นักพัฒนาก็จะคลานเข่าเข้าสวามิภักดิ์และหมอบกราบกลางสายฝน แล้วที่ยืนของภาษาที่ไม่เก๋าพอหละอยู่ตรงไหน?
เมื่อภาษาใหม่นั้นเจ๋งกว่า หากภาษาเก่ายังคงนั่งเล่นหมากเก็บอย่างสบายใจ โดยไม่พัฒนาโครงสร้างทางภาษาให้ดีขึ้น ซักวันก็คงไม่ต่างกับหลุมดำไกลโพ้น ที่ไม่มีใครมองเห็น ไม่มีใครสนใจ แม้ตัวเองจะมีแรงดึงดูดมากเพียงใด ก็มิอาจฉุนรั้งใครได้
JavaScript เป็นหนึ่งในภาษาเก่าแก่จนหงอกหลุดไปหลายเส้นละ ที่พัฒนาตามมาตรฐานของ ECMAScript โดยได้รับการพัฒนาเรื่อยมาจนก้าวกระโดดอย่างสูงในมาตรฐานของ ES2015 และยังคงได้รับการพัฒนาเรื่อยมาจนถึงปี 2017 (ES2017) ในปัจจุบัน
เพื่อไม่ให้ JavaScript ต้องถูกทอดทิ้ง TC39 ผู้แลดูและดูแลมาตรฐานของ ECMAScript จึงต้องขับเคลื่อนให้มาตรฐานนี้เดินหน้าต่อไปในฐานะคู่แข่งที่ทัดเทียมกับภาษาแห่งโลกสมัยใหม่
บทความนี้ผมจะนำเสนอมาตรฐานทางภาษาใหม่ๆของ ECMAScript ที่อาจจะถูกเพิ่มในอนาคต การที่เราได้รู้ฟีเจอร์เหล่านี้ล่วงหน้านอกจากจะเพิ่มความ Geek ให้ไปอวดเบ่งสาวได้แล้ว มันยังทำให้โลกทรรศน์ของเรากว้างขึ้นอีกด้วย
สำหรับเพื่อนๆที่สนใจกระบวนการพัฒนา ECMAScript ว่ากว่าจะออกมาเป็นมาตรฐานได้นั้นต้องบุกป่าฝ่าดงยังไงบ้าง เสพลิงก์นี้ซิ รอไร!
พูดกันมาหลายย่อหน้าแล้ว ไปดูกันดีกว่าว่าไวยากรณ์ที่ "อาจ" จะถูกเพิ่มเข้ามานี้ มีอะไรน่าสนใจบ้าง
Private Fields ชาตินี้จะได้ใช้ไหม
แม้ ES2015 จะมาพร้อมกับความสามารถของคลาส แต่ private fields ก็เป็นแค่อสุจิตัวจิ๋วที่หาไข่ไม่เจอซักที โปรแกรมเมอร์หลายคนจึงเลือก "มโน" ด้วยการใส่ _
นำหน้าชื่อฟิลด์ พร้อมทั้งชักชวนให้ผองเพื่อน "เออออห่อหมก" ว่านี่คือ private fields นะเออ
1class Article {2 constructor(title, body) {3 this.title = title4 this.body = body56 // อันนี้ private field นะ7 // อย่าเถียงดิไม่เห็น _ รึ ไอ้หอยขม!8 this._id = uuid.v4()9 }10}
รสชาติมันก็จะแปลกๆหน่อย แต่สารภาพมาเถอะว่าคุณก็ใช้~
เรามีความพยายามที่จะซ่อนข้อมูลกันมานานแล้วครับ วิธีการก็มีทั้งดีบ้างแย่บ้างคละเข่งกันไป หากเพื่อนๆคนไหนสนใจในรายละเอียด วาปอยู่นี่กับบทความ Private Fields ใน JavaScript: จาก ES5 สู่ ECMAScript Proposal
เพื่อหยุดความสิ้นหวังของโลกใบนี้ ภายใต้การกำกับของ ECMAScript จึงมีการเสนอมาตรฐานของการสร้าง private fields ด้วยการใช้เครื่องหมาย #
นำหน้าชื่อ
1class Point {23 #x;4 #y;56 constructor(x = 0, y = 0) {7 #x = +x;8 #y = +y;9 }1011 get x() { return #x }12 set x(value) { #x = +value }1314 get y() { return #y }15 set y(value) { #y = +value }1617 equals(p) { return #x === p.#x && #y === p.#y }1819 toString() { return `Point<${ #x },${ #y }>` }2021}
ก็กิ๊บเก๋ไปอีกแบบนะ แต่ก็ยังไม่วายที่จะมีกระทาชายผู้สงสัยว่าทำไมต้อง #
ใช้คำว่า private แบบภาษาอื่นมิได้ฤา หรือจะใช้ @
แบบภาษา Ruby งี้ไม่ได้หรอแว๊ ส่วนคำตอบของทีมงานจะเป็นเช่นไร เสพเอาเองที่นี่ครับ
Pipeline Operator เรียกต่อกัน ยาวไปยาวไป
เหนื่อยไหมกับการส่งค่าข้ามไปมาระหว่างฟังก์ชันหลายๆรอบ
1// ฟังก์ชันทำตัวอักษรแรกให้เป็นตัวพิมพ์ใหญ่2const capitalize = (str) => str[0].toUpperCase() + str.substring(1)34// แปลง - เป็นช่องว่าง5const convertDashToSpace = (str) => str.replace(/-/g, ' ')67// เราต้องการแปลงข้อความจาก8// introduction-to-pipeline-operator9// ให้เป็น Introduction to pipeline operator10const slug = 'introduction-to-pipeline-operator'11const slugWithoutDash = convertDashToSpace(slug)12const sentenceCaseTitle = capitalize(slugWithoutDash)1314console.log(sentenceCaseTitle) // Introduction to pipeline operator
ลากเลือดมาก กว่าจะได้ผลลัพธ์ต้องตรากตรำประกาศตัวแปรมารองรับมากมาย งั้นเอาใหม่
1const slug = 'introduction-to-pipeline-operator'23capitalize(convertDashToSpace(slug))
ด้วยพลานุภาพของการประกอบฟังก์ชันทำให้เราไม่ต้องประกาศตัวแปรคั่นกลาง แต่กระนั้นก็แลกมาด้วยโค้ดที่อ่านยากขึ้น
ภาษาตระกูล functional หลายภาษาลอกเลียนแบบการใช้งาน pipe มาจาก UNIX เช่นภาษา Elixir การใช้งาน pipe จะทำให้ผลลัพธ์ของการทำงานก่อนหน้าส่งไปเป็นพารามิเตอร์ตัวแรกของฟังก์ชันถัดไป
1slug |> convertDashToSpace |> capitalize
คุณแพะภูเขา เพียงการใช้งาน pipe operator (|>) ก็ทำให้โค้ดของเราอ่านง่ายขึ้น เราทราบได้ทันทีว่าค่าตั้งต้นของเราอยู่ในตัวแปร slug จากนั้นจึงส่งเข้าไปเป็นพารามิเตอร์ของ convertDashToSpace ผลลัพธ์จากการทำงานก็ส่งต่อไปให้ capitalize ดีงามแบบนี้ ต่อให้ไม่มีของแถมก็ซื้อเลย!
ฟีเจอร์ทางภาษาดีๆแบบนี้ มีหรือ ES จะไม่อยากคัดลอก ด้วยวิญญาณความเป็นจีนเซินเจิ้นในตัว ทีมงาน TC39 ผู้พัฒนา ECMAScript จึงก็อบปี้และแปะให้ใช้งานได้ดังนี้
1let result = slug |> convertDashToSpace |> capitalize
ไม่ต้องสืบ โค้ดเดียวกันนั่นละ!
Pattern Matching ก็มี
ภาษาตระกูล functional (อีกละ) ก็มีคอนเซ็ปต์ของ Pattern Matching เพราะความเซินเจิ้นในกระแสเลือดนั้นข้นกว่าน้ำ TC39 จึงมีแนวคิดที่จะเพิ่มสิ่งนี้ให้กับตัวภาษา
สมมติเรามีรูปร่าง (shape) อันนึง รูปนี้อาจเป็นสามเหลี่ยมก็ได้ เป็นสี่เหลี่ยมเหมือนหน้าอดีตท่านผู้นำก็ย่อมได้ เราจึงต้องมีการตรวจสอบอ็อบเจ็กต์รูปร่างของเราซะหน่อยว่ามีคุณสมบัติเป็นเช่นไร ก่อนทำการหาพื้นที่ต่อไป
1const shape = { width: 10, height: 20 }23function findArea() {4 // ถ้ามี width และ height แสดงว่าเป็นสี่เหลียม5 if (shape.width && shape.height) {6 return shape.width * shape.height7 }89 // แต่ถ้ามี height และ base ต้องเป็นสามเหลี่ยมแน่ๆ10 if (shape.height && shape.base) {11 return 0.5 * shape.height * shape.base12 }13}
ทว่า Pattern Matching ทำให้เราเข้าคู่อ็อบเจ็กต์เหมือนที่เราเข้าขากับคู่เดทได้อย่างดี โค้ดของเราจึงกรุบกรอบได้มากขึ้นโดยไม่ต้องผสมบอแร็กซ์เลยละ
1const shape = { width: 10, height: 20 }23function 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 ก็มา
จินตนาการถึงการแสดงผลชื่อถนนของเราจากอ็อบเจ็กต์ต่อไปนี้
1const user = {2 address: { street: 'XYZ' },3}
พระเจ้าก็ไม่รู้ บางทีในอ็อบเจ็กต์ของ user อาจไม่มี address อยู่ก็ได้ แม้จะมี address ก็ไม่มีหลักประกันว่า street จะมีอยู่เช่นกัน
เพื่อให้เราแสดงผล street โดยไม่เกิดข้อผิดพลาด เราจึงต้องตรวจสอบเสียก่อนว่าภายใต้ user นั้นมี address ดังนี้
1const street = user.address && user.address.street
ในภาษาอื่นๆเช่น Ruby เรามีสิ่งที่เรียกว่าเป็น Safe navigation operator ที่จะช่วยให้โค้ดอ่านง่ายขึ้น
1# หาก user ไม่มี address ก็จะคืน nil ไม่พ่น error2# หาก address ไม่มี street ก็จะคืน nil ไม่พ่น error3const street = user&.address&.street
ด้วยมาตรฐานที่เรากำลังพูดถึง ECMAScript จะมีตัวดำเนินการ ?.
ที่เรียกว่า Optional Chaining operator เพื่อใช้จัดการตามสิ่งที่เราพูดถึงกันในหัวข้อนี้
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 ก็มา
- เอกสารอ้างอิง