From 30fa3d7bf9e51d25bcffaed15a2538bbd11c1362 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Thu, 28 Mar 2024 00:23:44 +0700 Subject: [PATCH] Refactor code to improve performance and readability --- .../12-nullish-coalescing-operator/article.md | 111 +++++++++--------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/1-js/02-first-steps/12-nullish-coalescing-operator/article.md b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md index 11ba5dcac..d405dbda2 100644 --- a/1-js/02-first-steps/12-nullish-coalescing-operator/article.md +++ b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md @@ -1,69 +1,69 @@ -## ตัวดำเนินการ Nullish Coalescing '??' +# ตัวดำเนินการรวม Nullish '??' [recent browser="new"] -ตัวดำเนินการ Nullish Coalescing เขียนด้วยเครื่องหมายคำถามสองตัว `??` +ตัวดำเนินการรวม nullish เขียนด้วยเครื่องหมายคำถามสองตัวติดกัน `??` -เนื่องจากตัวดำเนินการนี้ถือว่า `null` และ `undefined` คล้ายคลึงกัน เราจะใช้คำศัพท์พิเศษที่นี่ ในบทความนี้ เพื่อความกระชับ เราจะบอกว่าค่า "กำหนด" เมื่อไม่ใช่ `null` หรือ `undefined` +ในบทความนี้เราจะใช้ศัพท์เฉพาะ เนื่องจาก `null` และ `undefined` ถูกจัดการในลักษณะคล้ายกัน เพื่อให้กระชับ เราจะเรียกว่าค่าหนึ่ง "ถูกกำหนด" เมื่อไม่ใช่ทั้ง `null` และ `undefined` -ผลลัพธ์ของ `a ?? b` คือ: -- ถ้า `a` ถูกกำหนด ให้คืนค่า `a` -- ถ้า `a` ไม่ถูกกำหนด ให้คืนค่า `b` +ผลลัพธ์ของ `a ?? b` จะเป็น: +- ถ้า `a` ถูกกำหนด ผลลัพธ์คือ `a` +- ถ้า `a` ไม่ถูกกำหนด ผลลัพธ์คือ `b` -กล่าวอีกนัยหนึ่ง `??` จะส่งคืนอาร์กิวเมนต์แรกถ้าไม่ใช่ `null/undefined` มิฉะนั้นจะส่งคืนอาร์กิวเมนต์ที่สอง +อีกนัยหนึ่ง `??` จะคืนอาร์กิวเมนต์ตัวแรก ถ้าไม่ใช่ `null/undefined` ไม่เช่นนั้นจะคืนตัวที่สอง -ตัวดำเนินการ Nullish Coalescing ไม่ใช่สิ่งใหม่ทั้งหมด มันเป็นเพียงไวยากรณ์ที่สวยงามเพื่อรับค่า "กำหนด" แรกของทั้งสอง +ตัวดำเนินการรวม nullish ไม่ใช่เรื่องใหม่ เป็นเพียงไวยากรณ์ที่สะดวกในการหาค่าแรกที่ "ถูกกำหนด" จากสองค่า -เราสามารถเขียน `result = a ?? b` ใหม่โดยใช้ตัวดำเนินการที่เรารู้จักอยู่แล้ว ดังนี้: +เราสามารถเขียน `result = a ?? b` ใหม่โดยใช้ตัวดำเนินการที่คุ้นเคยแล้วได้ดังนี้: ```js result = (a !== null && a !== undefined) ? a : b; ``` -ตอนนี้ชัดเจนแล้วว่า `??` ทำอะไร มาดูกันว่ามันช่วยอะไรได้บ้าง +ตอนนี้น่าจะชัดเจนแล้วว่า `??` ทำอะไร มาดูกันว่ามันมีประโยชน์อย่างไรบ้าง -กรณีการใช้งานทั่วไปของ `??` คือการกำหนดค่าเริ่มต้น +กรณีใช้งานทั่วไปของ `??` คือการกำหนดค่าเริ่มต้น (default) -ตัวอย่างเช่น ที่นี่เราแสดง `user` ถ้าค่าไม่ใช่ `null/undefined` มิฉะนั้นจะแสดง `Anonymous`: +ตัวอย่างเช่น ตรงนี้เราจะแสดง `user` ถ้าค่าไม่ใช่ `null/undefined` ไม่อย่างนั้นจะแสดง `Anonymous`: ```js run let user; -alert(user ?? "Anonymous"); // Anonymous (user is undefined) +alert(user ?? "Anonymous"); // Anonymous (user เป็น undefined) ``` -นี่คือตัวอย่างที่มีการกำหนดชื่อให้กับ `user`: +นี่คือตัวอย่างที่กำหนด `user` เป็นชื่อ: ```js run let user = "John"; -alert(user ?? "Anonymous"); // John (user is not null/undefined) +alert(user ?? "Anonymous"); // John (user ไม่ใช่ null/undefined) ``` -เราสามารถใช้ลำดับของ `??` เพื่อเลือกค่าแรกจากรายการที่ไม่ใช่ `null/undefined` +เรายังสามารถใช้ `??` หลายตัวต่อกัน เพื่อเลือกค่าแรกจาก list ที่ไม่ใช่ `null/undefined` ได้ด้วย -สมมติว่าเรามีข้อมูลของผู้ใช้ในตัวแปร `firstName`, `lastName` หรือ `nickName` ทั้งหมดนี้อาจไม่ถูกกำหนด ถ้าผู้ใช้ตัดสินใจไม่กรอกค่าที่เกี่ยวข้อง +สมมติเรามีข้อมูลผู้ใช้ในตัวแปร `firstName`, `lastName` หรือ `nickName` ซึ่งอาจไม่ถูกกำหนดค่า หากผู้ใช้ไม่ได้กรอกข้อมูลที่เกี่ยวข้อง -เราต้องการแสดงชื่อผู้ใช้โดยใช้ตัวแปรเหล่านี้ตัวใดตัวหนึ่ง หรือแสดง "Anonymous" ถ้าทั้งหมดเป็น `null/undefined` +เราต้องการแสดงชื่อผู้ใช้จากตัวแปรเหล่านี้ตัวใดตัวหนึ่ง หรือแสดง "Anonymous" ถ้าทุกตัวเป็น `null/undefined` -ลองใช้ตัวดำเนินการ `??` สำหรับสิ่งนั้น: +มาใช้ตัวดำเนินการ `??` กันเลย: ```js run let firstName = null; let lastName = null; let nickName = "Supercoder"; -// แสดงค่าที่กำหนดตัวแรก: +// แสดงค่าแรกที่ถูกกำหนด: *!* alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder -*/!* +*/!* ``` ## เปรียบเทียบกับ || -ตัวดำเนินการ OR `||` สามารถใช้ในลักษณะเดียวกับ `??` ตามที่อธิบายไว้ใน บทก่อนหน้า: info:logical-operators#or-finds-the-first-truthy-value +ตัวดำเนินการ OR `||` สามารถใช้ได้ในทำนองเดียวกับ `??` ตามที่อธิบายไว้ใน[บทก่อนหน้า](info:logical-operators#or-finds-the-first-truthy-value) -ตัวอย่างเช่น ในโค้ดข้างต้น เราสามารถแทนที่ `??` ด้วย `||` และยังคงได้ผลลัพธ์เดียวกัน: +เช่น ในโค้ดข้างต้น เราสามารถแทนที่ `??` ด้วย `||` โดยยังได้ผลลัพธ์เหมือนเดิม: ```js run let firstName = null; @@ -76,19 +76,19 @@ alert(firstName || lastName || nickName || "Anonymous"); // Supercoder */!* ``` -ในอดีต ตัวดำเนินการ OR `||` อยู่ก่อน มันมีมาตั้งแต่ต้นของ JavaScript ดังนั้นนักพัฒนาจึงใช้มันเพื่อวัตถุประสงค์ดังกล่าวมาเป็นเวลานาน +ย้อนไปในอดีต ตัวดำเนินการ OR `||` มีมาก่อนตั้งแต่ JavaScript เริ่มต้น นักพัฒนาจึงใช้มันเพื่อวัตถุประสงค์แบบนี้มานาน -ในทางกลับกัน ตัวดำเนินการ Nullish Coalescing `??` เพิ่งถูกเพิ่มเข้ามาใน JavaScript เมื่อไม่นานมานี้ และเหตุผลก็คือผู้คนไม่ค่อยพอใจกับ `||` +ในทางกลับกัน ตัวดำเนินการรวม nullish `??` เพิ่งถูกเพิ่มเข้ามาใน JavaScript ไม่นานมานี้ สาเหตุเพราะคนไม่ค่อยพอใจกับ `||` นัก -ความแตกต่างที่สำคัญระหว่างทั้งสองคือ: -- `||` จะส่งคืนค่า *truthy* ตัวแรก -- `??` จะส่งคืนค่า *defined* ตัวแรก +ความแตกต่างสำคัญระหว่างสองตัวนี้คือ: +- `||` คืนค่า *truthy* ตัวแรก +- `??` คืนค่าแรกที่ *ถูกกำหนด* -กล่าวอีกนัยหนึ่ง `||` ไม่แยกแยะระหว่าง `false`, `0`, สตริงว่าง `""` และ `null/undefined` พวกมันทั้งหมดเหมือนกัน -- ค่า falsy ถ้าใดๆ เหล่านี้เป็นอาร์กิวเมนต์แรกของ `||` เราจะได้อาร์กิวเมนต์ที่สองเป็นผลลัพธ์ +อีกนัยหนึ่ง `||` ไม่ได้แยกความแตกต่างระหว่าง `false`, `0`, string ว่าง `""` และ `null/undefined` มันถือว่าทั้งหมดเป็นค่า falsy เหมือนกัน ถ้าตัวใดตัวหนึ่งเป็น argument ตัวแรกของ `||` เราจะได้ argument ตัวที่สองเป็นผลลัพธ์ -อย่างไรก็ตาม ในทางปฏิบัติ เราอาจต้องการใช้ค่าเริ่มต้นเฉพาะเมื่อตัวแปรเป็น `null/undefined` นั่นคือ เมื่อค่าไม่รู้จัก/ไม่ได้ตั้งค่าจริงๆ +แต่ในทางปฏิบัติ เราอาจต้องการใช้ค่าเริ่มต้นก็ต่อเมื่อตัวแปรเป็น `null/undefined` นั่นคือเมื่อไม่รู้ค่าจริงๆ/ไม่ได้ถูกกำหนด -ตัวอย่างเช่น ลองพิจารณาสิ่งนี้: +ตัวอย่างเช่น พิจารณาโค้ดนี้: ```js run let height = 0; @@ -96,32 +96,33 @@ let height = 0; alert(height || 100); // 100 alert(height ?? 100); // 0 ``` -- `height || 100` ตรวจสอบ `height` ว่าเป็นค่า falsy หรือไม่ และเป็น `0` ซึ่งเป็นค่า falsy จริงๆ - - ดังนั้นผลลัพธ์ของ `||` คืออาร์กิวเมนต์ที่สอง `100` -- `height ?? 100` ตรวจสอบ `height` ว่าเป็น `null/undefined` หรือไม่ และไม่ใช่ - - ดังนั้นผลลัพธ์คือ `height` "ตามที่เป็นอยู่" นั่นคือ `0` -ในทางปฏิบัติ `height` เป็นศูนย์มักจะเป็นค่าที่ถูกต้อง ไม่ควรแทนที่ด้วยค่าเริ่มต้น ดังนั้น `??` ทำสิ่งที่ถูกต้อง +- `height || 100` ตรวจสอบว่า `height` เป็นค่า falsy หรือไม่ ซึ่ง `0` ก็ถือเป็น falsy จริงๆ + - ดังนั้นผลลัพธ์ของ `||` คือ argument ตัวที่สอง `100` +- `height ?? 100` ตรวจสอบว่า `height` เป็น `null/undefined` หรือไม่ ซึ่งไม่ใช่ + - ดังนั้นผลลัพธ์คือ `height` "ตามที่เป็น" คือ `0` + +ในทางปฏิบัติ ความสูงเป็นศูนย์มักเป็นค่าที่ถูกต้อง ไม่ควรถูกแทนที่ด้วยค่าเริ่มต้น ดังนั้น `??` จึงให้ผลลัพธ์ที่ถูกต้องพอดี ## ลำดับความสำคัญ -ลำดับความสำคัญของตัวดำเนินการ `??` เท่ากับ `||` ทั้งคู่มีค่าเท่ากับ `3` ในตาราง MDN: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table) +ตัวดำเนินการ `??` มีลำดับความสำคัญเท่ากับ `||` ทั้งคู่มีค่าเท่ากับ `3` ในตาราง [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table) -นั่นหมายความว่า เช่นเดียวกับ `||` ตัวดำเนินการ Nullish Coalescing `??` จะถูกประเมินก่อน `=` และ `?` แต่หลังจากการดำเนินการอื่นๆ ส่วนใหญ่ เช่น `+`, `*` +นั่นหมายความว่า เช่นเดียวกับ `||` ตัวดำเนินการรวม nullish `??` จะถูกประเมินก่อน `=` และ `?` แต่หลังการดำเนินการอื่นๆ ส่วนใหญ่ เช่น `+`, `*` -ดังนั้น เราอาจต้องเพิ่มวงเล็บในนิพจน์เช่นนี้: +ดังนั้นในนิพจน์แบบนี้ เราอาจต้องใส่วงเล็บเพิ่ม: ```js run let height = null; let width = null; -// สิ่งสำคัญ: ใช้วงเล็บ +// สำคัญ: ใช้วงเล็บ let area = (height ?? 100) * (width ?? 50); alert(area); // 5000 ``` -มิฉะนั้น ถ้าเราละเว้นวงเล็บ เนื่องจาก `*` มีลำดับความสำคัญสูงกว่า `??` มันจะทำงานก่อน ทำให้ผลลัพธ์ไม่ถูกต้อง +ไม่เช่นนั้น ถ้าเราละวงเล็บ เนื่องจาก `*` มีลำดับความสำคัญสูงกว่า `??` มันจะถูกประเมินก่อน ทำให้ได้ผลลัพธ์ไม่ถูกต้อง ```js // ไม่มีวงเล็บ @@ -131,23 +132,23 @@ let area = height ?? 100 * width ?? 50; let area = height ?? (100 * width) ?? 50; ``` -### ใช้ ?? ร่วมกับ && หรือ || +### การใช้ ?? ร่วมกับ && หรือ || -ด้วยเหตุผลด้านความปลอดภัย JavaScript ห้ามใช้ `??` ร่วมกับตัวดำเนินการ `&&` และ `||` เว้นแต่ลำดับความสำคัญจะระบุไว้ชัดเจนด้วยวงเล็บ +ด้วยเหตุผลด้านความปลอดภัย JavaScript ไม่อนุญาตให้ใช้ `??` ร่วมกับตัวดำเนินการ `&&` และ `||` นอกจากจะระบุลำดับความสำคัญชัดเจนด้วยวงเล็บ -โค้ดด้านล่างนี้จะทำให้เกิดข้อผิดพลาดทางไวยากรณ์: +โค้ดด้านล่างจะทำให้เกิด syntax error: ```js run let x = 1 && 2 ?? 3; // Syntax error ``` -สิ่งนี้เป็นข้อจำกัดของภาษา มันถูกเพิ่มเข้าไปในสเปกภาษาเพื่อวัตถุประสงค์ในการหลีกเลี่ยงข้อผิดพลาดในการเขียนโปรแกรม เมื่อผู้คนเริ่มเปลี่ยนจาก `||` เป็น `??` +ข้อจำกัดนี้อาจโต้แย้งได้ แต่ถูกเพิ่มเข้ามาในข้อกำหนดภาษา เพื่อหลีกเลี่ยงข้อผิดพลาดในการเขียนโปรแกรม เมื่อคนเริ่มเปลี่ยนจาก `||` มาใช้ `??` -ใช้วงเล็บเพื่อแก้ไขปัญหา: +ใช้วงเล็บให้ชัดเจนเพื่อแก้ปัญหา: ```js run *!* -let x = (1 && 2) ?? 3; // Works +let x = (1 && 2) ?? 3; // ใช้ได้ */!* alert(x); // 2 @@ -155,14 +156,14 @@ alert(x); // 2 ## สรุป -- ตัวดำเนินการ Nullish Coalescing `??` ช่วยให้เรากำหนดค่าเริ่มต้นให้กับตัวแปรได้อย่างง่ายดาย ในการเลือกค่า "defined" แรกจากรายการ +- ตัวดำเนินการรวม nullish `??` ให้วิธีที่กระชับในการเลือกค่าแรกที่ "ถูกกำหนด" จาก list - ใช้เพื่อกำหนดค่าเริ่มต้นให้กับตัวแปร: + มันมักถูกใช้เพื่อกำหนดค่าเริ่มต้นให้ตัวแปร: - ```js - // ตั้งค่า height=100, ถ้า height เป็น null หรือ undefined - height = height ?? 100; - ``` + ```js + // กำหนด height=100 ถ้า height เป็น null หรือ undefined + height = height ?? 100; + ``` -- ตัวดำเนินการ `??` มีลำดับความสำคัญต่ำมาก สูงกว่า `?` และ `=` เล็กน้อย ดังนั้นควรพิจารณาเพิ่มวงเล็บเมื่อใช้ในนิพจน์ -- ห้ามใช้กับ `||` หรือ `&&` โดยไม่มีวงเล็บ \ No newline at end of file +- ตัวดำเนินการ `??` มีลำดับความสำคัญต่ำมาก สูงกว่า `?` และ `=` เพียงเล็กน้อย ดังนั้นควรใส่วงเล็บเมื่อใช้ในนิพจน์ +- ห้ามใช้ร่วมกับ `||` หรือ `&&` โดยไม่ใส่วงเล็บให้ชัดเจน \ No newline at end of file