From d5745e93f23dc11cdd49d8b95c493ac78113b9a3 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 22:02:25 +0700 Subject: [PATCH 01/10] =?UTF-8?q?=E0=B8=9F=E0=B8=B1=E0=B8=87=E0=B8=81?= =?UTF-8?q?=E0=B9=8C=E0=B8=8A=E0=B8=B1=E0=B8=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../15-function-basics/article.md | 519 +----------------- 1 file changed, 15 insertions(+), 504 deletions(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index b771da221..c08cee927 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -1,18 +1,18 @@ # ฟังก์ชัน -บ่อยครั้งที่เราต้องการทำการกระทำที่คล้ายกันในหลาย ๆ ที่ของสคริปต์ +บ่อยครั้งที่เราต้องทำการกระทำที่คล้ายๆ กันในหลายๆ ที่ของสคริปต์ -ยกตัวอย่างเช่น เราต้องการแสดงข้อความที่ดูดีเมื่อผู้ใช้เข้าสู่ระบบ ออกจากระบบ หรืออาจจะที่อื่นๆ อีก +เช่น เราอาจต้องแสดงข้อความที่ดูดีเมื่อผู้ใช้ล็อกอิน ล็อกเอาท์ หรือที่อื่นๆ -ฟังก์ชันเป็น "building blocks" หลักของโปรแกรม มันช่วยให้โค้ดถูกเรียกใช้ซ้ำได้หลายครั้งโดยไม่ต้องเขียนซ้ำๆ กัน +ฟังก์ชันคือ "บล็อกสร้าง" หลักของโปรแกรม มันทำให้เราเรียกใช้โค้ดได้หลายครั้งโดยไม่ต้องเขียนซ้ำ -เราได้เห็นตัวอย่างของฟังก์ชันที่มีอยู่แล้วในภาษา เช่น `alert(message)`, `prompt(message, default)` และ `confirm(question)` แต่เราก็สามารถสร้างฟังก์ชันของเราเองได้เช่นกัน +เราเคยเห็นตัวอย่างฟังก์ชันที่มีมาในตัวแล้ว เช่น `alert(message)`, `prompt(message, default)` และ `confirm(question)` แต่เราก็สามารถสร้างฟังก์ชันของตัวเองได้ด้วย ## การประกาศฟังก์ชัน -เราสามารถสร้างฟังก์ชันโดยใช้ *function declaration* +ในการสร้างฟังก์ชัน เราสามารถใช้ *การประกาศฟังก์ชัน* -มีรูปแบบดังนี้: +ซึ่งมีรูปแบบดังนี้: ```js function showMessage() { @@ -20,17 +20,17 @@ function showMessage() { } ``` -คำสำคัญ `function` มาก่อน ตามด้วย *ชื่อของฟังก์ชัน* จากนั้นเป็นรายการของ *พารามิเตอร์* ภายในวงเล็บ (คั่นด้วยเครื่องหมายจุลภาค ในตัวอย่างด้านบนไม่มี จะเห็นตัวอย่างในภายหลัง) และสุดท้ายคือโค้ดของฟังก์ชัน หรือเรียกว่า "function body" ซึ่งอยู่ในวงเล็บปีกกา +ใช้คีย์เวิร์ด `function` ก่อน ตามด้วย*ชื่อฟังก์ชัน* แล้วก็รายการ *parameter* ในวงเล็บ (คั่นด้วยเครื่องหมายจุลภาค ในตัวอย่างข้างบนจะเว้นว่าง เดี๋ยวจะมีตัวอย่างอีกทีหลัง) สุดท้ายคือโค้ดของฟังก์ชันระหว่างปีกกาปิดเปิด ที่เรียกว่า "ตัวฟังก์ชัน" หรือ "function body" ```js -function ชื่อ(parameter1, parameter2, ... parameterN) { - // body +function name(parameter1, parameter2, ... parameterN) { + // ตัวฟังก์ชัน } ``` -ฟังก์ชันใหม่ของเราสามารถเรียกใช้ได้โดยระบุชื่อของมัน: `showMessage()` +ฟังก์ชันใหม่ของเราสามารถเรียกใช้ได้ด้วยชื่อของมัน เช่น: `showMessage()` -ตัวอย่างเช่น: +ดังตัวอย่าง: ```js run function showMessage() { @@ -40,500 +40,11 @@ function showMessage() { *!* showMessage(); showMessage(); -*/!* +*/!* ``` -การเรียก `showMessage()` จะทำให้โค้ดในฟังก์ชันทำงาน ในที่นี้เราจะเห็นข้อความสองครั้ง +เมื่อเรียก `showMessage()` ก็จะรันโค้ดในตัวฟังก์ชัน ในที่นี้เราจะเห็นข้อความถูกแสดงสองครั้ง -ตัวอย่างนี้แสดงถึงจุดประสงค์หลักอย่างหนึ่งของฟังก์ชันได้อย่างชัดเจน นั่นคือการหลีกเลี่ยงการซ้ำซ้อนของโค้ด +ตัวอย่างนี้แสดงให้เห็นวัตถุประสงค์หลักอย่างหนึ่งของฟังก์ชัน นั่นคือเพื่อหลีกเลี่ยงการเขียนโค้ดซ้ำ -ถ้าเราต้องการเปลี่ยนข้อความหรือวิธีการแสดงผล เราแค่แก้โค้ดในที่เดียว นั่นคือฟังก์ชันที่ใช้แสดงผลข้อความ - -## ตัวแปรภายในฟังก์ชัน - -ตัวแปรที่ประกาศภายในฟังก์ชันจะมองเห็นได้เฉพาะภายในฟังก์ชันนั้นๆ - -ตัวอย่างเช่น: - -```js run -function showMessage() { -*!* - let message = "สวัสดี ผมคือ JavaScript!"; // ตัวแปรภายใน -*/!* - - alert( message ); -} - -showMessage(); // สวัสดี ผมคือ JavaScript! - -alert( message ); // <-- เกิด Error! ตัวแปรอยู่เฉพาะในฟังก์ชัน -``` - -## ตัวแปรภายนอก - -ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้ด้วย ตัวอย่างเช่น: - -```js run no-beautify -let *!*userName*/!* = 'John'; - -function showMessage() { - let message = 'สวัสดี ' + *!*userName*/!*; - alert(message); -} - -showMessage(); // สวัสดี John -``` - -ฟังก์ชันมีการเข้าถึงตัวแปรภายนอกได้อย่างเต็มที่ มันสามารถแก้ไขค่าได้ด้วย - -ตัวอย่างเช่น: - -```js run -let *!*userName*/!* = 'John'; - -function showMessage() { - *!*userName*/!* = "Bob"; // (1) เปลี่ยนตัวแปรภายนอก - - let message = 'สวัสดี ' + *!*userName*/!*; - alert(message); -} - -alert( userName ); // *!*John*/!* ก่อนเรียกฟังก์ชัน - -showMessage(); - -alert( userName ); // *!*Bob*/!*, ค่าถูกแก้ไขโดยฟังก์ชัน -``` - -ตัวแปรภายนอกจะถูกใช้ก็ต่อเมื่อไม่มีตัวแปรภายในที่ชื่อซ้ำกัน - -ถ้ามีตัวแปรที่ชื่อเหมือนกันถูกประกาศภายในฟังก์ชัน มันจะ *บดบัง* ตัวแปรภายนอก ตัวอย่างเช่น ในโค้ดด้านล่าง ฟังก์ชันจะใช้ `userName` ภายในฟังก์ชัน ส่วน `userName` ภายนอกจะถูกเพิกเฉย: - -```js run -let userName = 'John'; - -function showMessage() { -*!* - let userName = "Bob"; // ประกาศตัวแปรภายใน -*/!* - - let message = 'สวัสดี ' + userName; // *!*Bob*/!* - alert(message); -} - -// ฟังก์ชันจะสร้างและใช้ userName ของตัวเอง -showMessage(); - -alert( userName ); // *!*John*/!*, ไม่เปลี่ยนแปลง เพราะฟังก์ชันไม่ได้เข้าถึงตัวแปรภายนอก -``` - -```smart header="ตัวแปรส่วนกลาง (Global variables)" -ตัวแปรที่ประกาศนอกฟังก์ชัน เช่น `userName` ภายนอกในตัวอย่างด้านบน เรียกว่า *global* - -ตัวแปร global จะมองเห็นได้จากทุกฟังก์ชัน (ยกเว้นว่ามันจะถูกบดบังโดยตัวแปรภายใน) - -แนวทางที่ดีคือการลดการใช้ตัวแปร global การเขียนโค้ดสมัยใหม่มีการใช้ตัวแปร global น้อยมากหรือไม่มีเลย ตัวแปรส่วนใหญ่อยู่ภายในฟังก์ชัน แต่บางครั้งก็อาจจะมีประโยชน์ในการเก็บข้อมูลระดับโครงการ -``` - -## พารามิเตอร์ - -เราสามารถส่งค่าแบบใดๆ ก็ได้ไปยังฟังก์ชันโดยใช้พารามิเตอร์ - -ในตัวอย่างด้านล่าง ฟังก์ชันมีพารามิเตอร์สองตัวคือ: `from` และ `text` - -```js run -function showMessage(*!*from, text*/!*) { // พารามิเตอร์: from, text - alert(from + ': ' + text); -} - -*!*showMessage('แอน', 'สวัสดี!');*/!* // แอน: สวัสดี! (*) -*!*showMessage('แอน', 'เป็นยังไงบ้าง?');*/!* // แอน: เป็นยังไงบ้าง? (**) -``` - -เมื่อฟังก์ชันถูกเรียกใช้ในบรรทัด `(*)` และ `(**)` ค่าที่ส่งเข้าไปจะถูกคัดลอกไปยังตัวแปรภายในฟังก์ชันคือ `from` และ `text` จากนั้นฟังก์ชันก็จะใช้ค่าเหล่านั้น - -ต่อไปนี้เป็นอีกตัวอย่างหนึ่ง: เรามีตัวแปร `from` และส่งมันเข้าไปในฟังก์ชัน ข้อสังเกต: ฟังก์ชันเปลี่ยนค่า `from` แต่การเปลี่ยนแปลงนี้จะไม่มีผลต่อ `from` ภายนอก เพราะฟังก์ชันจะได้รับสำเนาของค่านั้นเสมอ - -```js run -function showMessage(from, text) { - -*!* - from = '*' + from + '*'; // ทำให้ "from" ดูดีขึ้น -*/!* - - alert( from + ': ' + text ); -} - -let from = "แอน"; - -showMessage(from, "สวัสดี"); // *แอน*: สวัสดี - -// ค่าของ "from" เหมือนเดิม ฟังก์ชันแก้ไขสำเนาภายในเท่านั้น -alert( from ); // แอน -``` - -เมื่อมีการส่งค่าเข้าไปในฟังก์ชันในรูปแบบของพารามิเตอร์ เราจะเรียกค่านั้นว่า *อาร์กิวเมนต์ (argument)* - -หรือพูดอีกอย่างคือ: - -- พารามิเตอร์คือตัวแปรที่ระบุไว้ในวงเล็บในการประกาศฟังก์ชัน (เป็นคำที่ใช้ในช่วงประกาศ) -- อาร์กิวเมนต์คือค่าที่ถูกส่งเข้าไปในฟังก์ชันเมื่อมีการเรียกใช้ (เป็นคำที่ใช้ในช่วงเรียกใช้) - -เราจะประกาศฟังก์ชันโดยระบุรายชื่อพารามิเตอร์ไว้ แล้วจึงเรียกใช้ฟังก์ชันโดยส่งอาร์กิวเมนต์เข้าไป - -ในตัวอย่างด้านบน อาจพูดได้ว่า: "ฟังก์ชัน `showMessage` ถูกประกาศด้วยพารามิเตอร์สองตัว แล้วจึงถูกเรียกใช้ด้วยอาร์กิวเมนต์สองค่า: `from` และ `"สวัสดี"`" - - -## ค่าเริ่มต้น - -ถ้าฟังก์ชันถูกเรียก แต่ไม่ได้รับอาร์กิวเมนต์ ค่าของพารามิเตอร์ที่ไม่ได้รับจะเป็น `undefined` - -ตัวอย่างเช่น ฟังก์ชัน `showMessage(from, text)` ที่กล่าวถึงก่อนหน้าสามารถถูกเรียกด้วยอาร์กิวเมนต์เดียวได้: - -```js -showMessage("แอน"); -``` - -นั่นไม่ใช่ข้อผิดพลาด ฟังก์ชันจะแสดงผลออกมาเป็น `"*แอน*: undefined"` เนื่องจากไม่มีการส่งค่าให้กับ `text` พารามิเตอร์ `text` จะมีค่าเริ่มต้นเป็น `undefined` - -เราสามารถระบุค่าเริ่มต้น (ที่จะใช้หากค่าไม่ถูกส่งเข้ามา) ให้กับพารามิเตอร์ในการประกาศฟังก์ชันได้ โดยใช้ `=`: - -```js run -function showMessage(from, *!*text = "ไม่มีข้อความ"*/!*) { - alert( from + ": " + text ); -} - -showMessage("แอน"); // แอน: ไม่มีข้อความ -``` - -ถ้าไม่มีการส่งค่าให้กับพารามิเตอร์ `text` ตอนนี้ พารามิเตอร์ `text` จะมีค่าเป็น `"ไม่มีข้อความ"` - -ค่าเริ่มต้นก็จะถูกใช้เช่นกันถ้าพารามิเตอร์มีอยู่ แต่มีค่าเป็น `undefined` อย่างเคร่งครัด เช่นนี้: - -```js -showMessage("แอน", undefined); // แอน: ไม่มีข้อความ -``` - -ในที่นี้ `"ไม่มีข้อความ"` เป็นสตริง แต่มันสามารถเป็นนิพจน์ที่ซับซ้อนมากกว่านี้ได้ ซึ่งจะถูกประเมินและกำหนดค่าก็ต่อเมื่อพารามิเตอร์ไม่ถูกส่งเข้ามาเท่านั้น ดังนั้น นี่ก็เป็นไปได้เช่นกัน: - -```js run -function showMessage(from, text = anotherFunction()) { - // anotherFunction() จะทำงานก็ต่อเมื่อไม่มี text ถูกส่งมา - // ผลลัพธ์จาก anotherFunction() จะกลายเป็นค่าของ text -} -``` - -```smart header="การประเมินค่าพารามิเตอร์เริ่มต้น" -ใน JavaScript พารามิเตอร์เริ่มต้นจะถูกประเมินทุกครั้งที่ฟังก์ชันถูกเรียกโดยไม่ส่งพารามิเตอร์ที่เกี่ยวข้องเข้ามา - -ในตัวอย่างด้านบน `anotherFunction()` จะไม่ถูกเรียกเลย ถ้ามีการส่งพารามิเตอร์ `text` เข้ามา - -ในทางกลับกัน มันจะถูกเรียกแยกต่างหากทุกครั้งเมื่อไม่มี `text` ถูกส่งมา -``` - -````smart header="พารามิเตอร์เริ่มต้นในโค้ด JavaScript เก่า" -หลายปีก่อน JavaScript ไม่ได้รองรับ syntax สำหรับพารามิเตอร์เริ่มต้น ดังนั้นผู้คนจึงใช้วิธีอื่นๆ ในการกำหนดค่าเริ่มต้น - -ทุกวันนี้ เราอาจพบเจอวิธีเหล่านี้ในสคริปต์เก่าๆ - -ตัวอย่างเช่น การตรวจสอบ `undefined` อย่างชัดเจน: - -```js -function showMessage(from, text) { -*!* - if (text === undefined) { - text = 'ไม่มีข้อความ'; - } -*/!* - - alert( from + ": " + text ); -} -``` - -...หรือใช้ตัวดำเนินการ `||`: - -```js -function showMessage(from, text) { - // ถ้าค่าของ text เป็น falsy ให้กำหนดค่าเริ่มต้น - // นี่ถือว่า text == "" เท่ากับไม่ได้ส่ง text มาเลย - text = text || 'ไม่มีข้อความ'; - ... -} -``` -```` - - -### ทางเลือกอื่นสำหรับพารามิเตอร์เริ่มต้น - -บางครั้งก็สมเหตุสมผลที่จะกำหนดค่าเริ่มต้นให้กับพารามิเตอร์ในขั้นตอนถัดมาหลังจากประกาศฟังก์ชันแล้ว - -เราสามารถตรวจสอบได้ว่าพารามิเตอร์ถูกส่งเข้ามาหรือไม่ระหว่างการทำงานของฟังก์ชัน โดยนำค่าไปเปรียบเทียบกับ `undefined`: - -```js run -function showMessage(text) { - // ... - -*!* - if (text === undefined) { // ถ้าไม่มีพารามิเตอร์ - text = 'ข้อความว่าง'; - } -*/!* - - alert(text); -} - -showMessage(); // ข้อความว่าง -``` - -หรือเราสามารถใช้ตัวดำเนินการ `||`: - -```js -function showMessage(text) { - // ถ้า text เป็น undefined หรือ falsy อื่นๆ ให้กำหนดเป็น 'ว่าง' - text = text || 'ว่าง'; - ... -} -``` - -JavaScript engine สมัยใหม่รองรับ[ตัวดำเนินการ nullish coalescing](info:nullish-coalescing-operator) `??` ซึ่งดีกว่าเมื่อค่า falsy ส่วนใหญ่ เช่น `0` ควรถือว่า "ปกติ": - -```js run -function showCount(count) { - // ถ้า count เป็น undefined หรือ null ให้แสดง "ไม่ทราบ" - alert(count ?? "ไม่ทราบ"); -} - -showCount(0); // 0 -showCount(null); // ไม่ทราบ -showCount(); // ไม่ทราบ -``` - -## การส่งค่ากลับ - -ฟังก์ชันสามารถส่งค่ากลับไปยังโค้ดที่เรียกมันในรูปแบบของผลลัพธ์ได้ - -ตัวอย่างง่ายๆ คือฟังก์ชันที่รวมค่าสองค่าเข้าด้วยกัน: - -```js run no-beautify -function sum(a, b) { - *!*return*/!* a + b; -} - -let result = sum(1, 2); -alert( result ); // 3 -``` - -คำสั่ง `return` สามารถอยู่ในตำแหน่งใดๆ ของฟังก์ชันก็ได้ เมื่อการทำงานมาถึงจุดนั้น ฟังก์ชันจะหยุด และค่าจะถูกส่งกลับไปยังโค้ดที่เรียกใช้ (กำหนดค่าให้กับ `result` ในตัวอย่างด้านบน) - -ในฟังก์ชันเดียว อาจมีหลาย `return` ได้ ตัวอย่างเช่น: - -```js run -function checkAge(age) { - if (age >= 18) { -*!* - return true; -*/!* - } else { -*!* - return confirm('คุณได้รับอนุญาตจากพ่อแม่แล้วหรือยัง?'); -*/!* - } -} - -let age = prompt('คุณอายุเท่าไหร่?', 18); - -if ( checkAge(age) ) { - alert( 'อนุญาตให้เข้า' ); -} else { - alert( 'ไม่อนุญาตให้เข้า' ); -} -``` - -สามารถใช้ `return` โดยไม่มีค่าได้ ซึ่งจะทำให้ฟังก์ชันหยุดทำงานทันที - -ตัวอย่างเช่น: - -```js -function showMovie(age) { - if ( !checkAge(age) ) { -*!* - return; -*/!* - } - - alert( "กำลังแสดงหนังให้คุณดู" ); // (*) - // ... -} -``` - -ในโค้ดด้านบน ถ้า `checkAge(age)` ส่งค่ากลับเป็น `false` `showMovie` จะไม่ไปถึงคำสั่ง `alert` - -````smart header="ฟังก์ชันที่มี `return` ว่างๆ หรือไม่มี `return` เลยจะส่งค่ากลับเป็น `undefined`" -ถ้าฟังก์ชันไม่ส่งค่ากลับ ก็เหมือนกับว่ามันส่งค่า `undefined` กลับ: - -```js run -function doNothing() { /* ว่างๆ */ } - -alert( doNothing() === undefined ); // true -``` - -`return` ว่างๆ ก็เหมือนกับ `return undefined`: - -```js run -function doNothing() { - return; -} - -alert( doNothing() === undefined ); // true -``` -```` - -````warn header="ห้ามขึ้นบรรทัดใหม่ระหว่าง `return` กับค่าที่จะส่งกลับ" -สำหรับนิพจน์ยาวๆ ใน `return` มันอาจจะน่าลองขึ้นบรรทัดใหม่ เช่นนี้: - -```js -return - (some + long + expression + or + whatever * f(a) + f(b)) -``` -แต่นั่นไม่ทำงาน เพราะ JavaScript คิดว่ามีเครื่องหมายอัฒภาค (;) ต่อท้ายคำว่า `return` เสมอ มันจะทำงานเหมือนกับ: - -```js -return*!*;*/!* - (some + long + expression + or + whatever * f(a) + f(b)) -``` - -ดังนั้น มันก็จะกลายเป็น return ว่างๆ ไป - -ถ้าเราต้องการให้นิพจน์ที่ส่งกลับต่อเนื่องข้ามหลายบรรทัด เราควรเริ่มเขียนมันในบรรทัดเดียวกับคำว่า `return` หรืออย่างน้อยก็ต้องใส่วงเล็บเปิดไว้ที่นั่น ดังนี้: - -```js -return ( - some + long + expression - + or + - whatever * f(a) + f(b) - ) -``` -แบบนี้ก็จะทำงานตามที่เราคาดหวัง -```` - -## การตั้งชื่อฟังก์ชัน [#function-naming] - -ฟังก์ชันคือการกระทำ ดังนั้นชื่อของมันจึงมักจะเป็นคำกริยา ควรจะสั้นกระชับ แต่บอกได้แม่นยำมากที่สุดถึงสิ่งที่ฟังก์ชันทำ เพื่อคนที่อ่านโค้ดจะได้เข้าใจว่าฟังก์ชันนั้นทำอะไร - -การตั้งชื่อฟังก์ชันโดยใช้คำนำหน้าที่บอกคร่าวๆ ถึงการกระทำนั้นเป็นแนวปฏิบัติที่ใช้กันอย่างแพร่หลาย ทีมงานควรมีข้อตกลงกันเกี่ยวกับความหมายของคำนำหน้าเหล่านั้น - -ยกตัวอย่างเช่น ฟังก์ชันที่ขึ้นต้นด้วย `"show"` มักจะแสดงบางอย่าง - -ฟังก์ชันที่ขึ้นต้นด้วย... - -- `"get…"` -- ส่งค่ากลับ -- `"calc…"` -- คำนวณบางอย่าง -- `"create…"` -- สร้างบางอย่าง -- `"check…"` -- ตรวจสอบบางอย่างและส่งค่าบูลีนกลับ เป็นต้น - -ตัวอย่างชื่อฟังก์ชันแบบนี้: - -```js no-beautify -showMessage(..) // แสดงข้อความ -getAge(..) // ส่งค่าอายุกลับ (ไปเอามาจากไหนสักที่) -calcSum(..) // คำนวณผลรวมและส่งผลลัพธ์กลับ -createForm(..) // สร้างฟอร์ม (และส่วนใหญ่จะส่งค่ากลับ) -checkPermission(..) // ตรวจสอบสิทธิ์ และส่งค่า true/false กลับ -``` - -ด้วยการใส่คำนำหน้าไว้ การมองชื่อฟังก์ชันผ่านๆ ก็ทำให้เข้าใจได้ว่ามันทำงานแบบใด และส่งค่าแบบใดกลับ - -```smart header="ฟังก์ชันหนึ่งตัว -- การกระทำหนึ่งอย่าง" -ฟังก์ชันควรทำตามที่ชื่อของมันบอก ไม่ควรทำมากไปกว่านั้น - -สองการกระทำที่เป็นอิสระต่อกันมักควรแยกเป็นสองฟังก์ชัน แม้ว่าปกติจะถูกเรียกใช้ด้วยกันก็ตาม (ในกรณีนั้นเราอาจสร้างฟังก์ชันที่สามที่เรียกใช้ฟังก์ชันทั้งสองนั้น) - -ตัวอย่างของการฝ่าฝืนกฎนี้: - -- `getAge` -- จะไม่ดี ถ้ามันแสดง `alert` พร้อมอายุ (ควรเอาแค่อายุ) -- `createForm` -- จะไม่ดี ถ้ามันแก้ไข document โดยเพิ่มฟอร์มเข้าไป (ควรแค่สร้างและส่งฟอร์มกลับ) -- `checkPermission` -- จะไม่ดี ถ้ามันแสดงข้อความ `access granted/denied` (ควรทำเพียงการตรวจสอบและส่งผลลัพธ์กลับ) - -ตัวอย่างเหล่านี้สมมติความหมายทั่วไปของคำนำหน้า คุณและทีมของคุณอาจตกลงกันใช้ความหมายอื่นๆ ได้ แต่ปกติก็ไม่ค่อยแตกต่างกันมากนัก ไม่ว่ายังไง คุณควรมีความเข้าใจอย่างแน่นอนว่าคำนำหน้าแต่ละคำหมายถึงอะไร ฟังก์ชันที่มีคำนำหน้าสามารถทำอะไรได้บ้างและทำอะไรไม่ได้ ฟังก์ชันที่มีคำนำหน้าเดียวกันทั้งหมดควรทำตามกฎเดียวกัน และทีมควรแบ่งปันองค์ความรู้นี้กัน -``` - -```smart header="ชื่อฟังก์ชันที่สั้นมากๆ" -ฟังก์ชันที่ถูกใช้ *บ่อยมากๆ* บางครั้งอาจมีชื่อที่สั้นเป็นพิเศษ - -ตัวอย่างเช่น framework [jQuery](https://jquery.com/) กำหนดฟังก์ชันชื่อ `$` ส่วนไลบรารี [Lodash](https://lodash.com/) เรียกฟังก์ชันหลักของมันว่า `_` - -เหล่านี้เป็นข้อยกเว้น โดยทั่วไปแล้วชื่อฟังก์ชันควรจะกระชับและสื่อความหมาย -``` - -## ฟังก์ชัน == คอมเมนต์ - -ฟังก์ชันควรสั้นและทำสิ่งที่ต้องการอย่างเดียว ถ้าสิ่งนั้นใหญ่มาก อาจจะควรแยกฟังก์ชันออกเป็นฟังก์ชันเล็กๆ สองสามตัว บางทีการทำตามกฎนี้อาจจะไม่ง่ายนัก แต่มันเป็นสิ่งที่ดีอย่างแน่นอน - -ฟังก์ชันแยกต่างหากไม่ใช่แค่ทำให้ทดสอบและดีบั๊กง่ายขึ้น -- การมีอยู่ของมันเองก็เป็นคอมเมนต์ที่ดีมากแล้ว! - -ยกตัวอย่างเช่น ลองเปรียบเทียบฟังก์ชัน `showPrimes(n)` สองตัวด้านล่าง แต่ละตัวแสดงผล[จำนวนเฉพาะ](https://en.wikipedia.org/wiki/Prime_number)จนถึง `n` - -ตัวแรกใช้ label: - -```js -function showPrimes(n) { - nextPrime: for (let i = 2; i < n; i++) { - - for (let j = 2; j < i; j++) { - if (i % j == 0) continue nextPrime; - } - - alert( i ); // จำนวนเฉพาะ - } -} -``` - -ตัวที่สองใช้ฟังก์ชันเพิ่มเติม `isPrime(n)` เพื่อตรวจสอบว่าเป็นจำนวนเฉพาะหรือไม่: - -```js -function showPrimes(n) { - - for (let i = 2; i < n; i++) { - *!*if (!isPrime(i)) continue;*/!* - - alert(i); // จำนวนเฉพาะ - } -} - -function isPrime(n) { - for (let i = 2; i < n; i++) { - if ( n % i == 0) return false; - } - return true; -} -``` - -ตัวที่สองเข้าใจง่ายกว่าใช่ไหม? แทนที่จะมีชิ้นส่วนของโค้ด เราเห็นเป็นชื่อของการกระทำ (`isPrime`) บางครั้งคนเรียกโค้ดแบบนี้ว่า *self-describing* - -ดังนั้น ฟังก์ชันสามารถถูกสร้างขึ้นได้แม้ว่าเราจะไม่ต้องการเอามันไปใช้ซ้ำ มันช่วยจัดโครงสร้างโค้ดและทำให้โค้ดอ่านง่ายขึ้น - -## สรุป - -การประกาศฟังก์ชันมีหน้าตาดังนี้: - -```js -function name(parameters, delimited, by, comma) { - /* code */ -} -``` - -- ค่าที่ส่งเข้าไปในฟังก์ชันในรูปแบบของพารามิเตอร์จะถูกคัดลอกไปยังตัวแปรภายในของฟังก์ชัน -- ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้ แต่มันทำได้เฉพาะจากด้านในออกไปเท่านั้น โค้ดภายนอกฟังก์ชันจะไม่เห็นตัวแปรภายในของฟังก์ชัน -- ฟังก์ชันสามารถส่งค่ากลับได้ ถ้าไม่ส่ง ผลลัพธ์ของมันจะเป็น `undefined` - -เพื่อให้โค้ดสะอาดและเข้าใจง่าย แนะนำให้ใช้ตัวแปรภายในและพารามิเตอร์เป็นหลักในฟังก์ชัน ไม่ใช้ตัวแปรภายนอก - -การเข้าใจฟังก์ชันที่รับพารามิเตอร์ ทำงานกับพารามิเตอร์เหล่านั้น และส่งผลลัพธ์กลับ จะง่ายกว่าการเข้าใจฟังก์ชันที่ไม่รับพารามิเตอร์ แต่ไปแก้ไขตัวแปรภายนอกเป็น side effect - -การตั้งชื่อฟังก์ชัน: - -- ชื่อควรอธิบายอย่างชัดเจนว่าฟังก์ชันทำอะไร เมื่อเราเห็นการเรียกฟังก์ชันในโค้ด ชื่อที่ดีควรบอกได้ทันทีว่ามันทำอะไรและส่งอะไรกลับ -- ฟังก์ชันคือการกระทำ ดังนั้นชื่อฟังก์ชันจึงมักจะเป็นคำกริยา -- มีคำนำหน้าของฟังก์ชันที่รู้จักกันดีมากมาย เช่น `create…`, `show…`, `get…`, `check…` เป็นต้น ใช้พวกนี้เพื่อบอกใบ้ว่าฟังก์ชันทำอะไร - -ฟังก์ชันคือ building blocks หลักของสคริปต์ ตอนนี้เราได้ครอบคลุมพื้นฐานแล้ว ดังนั้นเรามีความรู้พอที่จะเริ่มสร้างและใช้ฟังก์ชันได้แล้ว แต่นั่นเป็นเพียงจุดเริ่มต้นของเส้นทางเท่านั้น เรายังจะย้อนกลับมาที่ฟังก์ชันอีกหลายครั้ง เพื่อเจาะลึกลงไปในฟีเจอร์ขั้นสูงของมัน \ No newline at end of file +ถ้าเราต้องการเปลี่ยนข้อความหรือวิธีแสดงผล ก็แค่แก้ไขโค้ดในที่เดียว นั่นคือในตัวฟังก์ชันที่ทำการแสดงผลมัน \ No newline at end of file From a29699dc9d92d89af6dd8f3dcc6e103d5cd048ec Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 22:08:42 +0700 Subject: [PATCH 02/10] =?UTF-8?q?=E0=B8=95=E0=B8=B1=E0=B8=A7=E0=B9=81?= =?UTF-8?q?=E0=B8=9B=E0=B8=A3=E0=B8=A0=E0=B8=B2=E0=B8=A2=E0=B9=83=E0=B8=99?= =?UTF-8?q?=E0=B8=9F=E0=B8=B1=E0=B8=87=E0=B8=81=E0=B9=8C=E0=B8=8A=E0=B8=B1?= =?UTF-8?q?=E0=B8=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../15-function-basics/article.md | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index c08cee927..89e237525 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -47,4 +47,90 @@ showMessage(); ตัวอย่างนี้แสดงให้เห็นวัตถุประสงค์หลักอย่างหนึ่งของฟังก์ชัน นั่นคือเพื่อหลีกเลี่ยงการเขียนโค้ดซ้ำ -ถ้าเราต้องการเปลี่ยนข้อความหรือวิธีแสดงผล ก็แค่แก้ไขโค้ดในที่เดียว นั่นคือในตัวฟังก์ชันที่ทำการแสดงผลมัน \ No newline at end of file +ถ้าเราต้องการเปลี่ยนข้อความหรือวิธีแสดงผล ก็แค่แก้ไขโค้ดในที่เดียว นั่นคือในตัวฟังก์ชันที่ทำการแสดงผลมัน + +## ตัวแปรภายในฟังก์ชัน (Local variables) + +ตัวแปรที่ประกาศภายในฟังก์ชัน จะมองเห็นได้เฉพาะภายในฟังก์ชันนั้นเท่านั้น + +ตัวอย่างเช่น: + +```js run +function showMessage() { +*!* + let message = "Hello, I'm JavaScript!"; // ตัวแปรท้องถิ่น +*/!* + + alert( message ); +} + +showMessage(); // Hello, I'm JavaScript! + +alert( message ); // <-- Error! ตัวแปรอยู่ภายในฟังก์ชัน ไม่สามารถเข้าถึงจากภายนอกได้ +``` + +## ตัวแปรภายนอก (Outer variables) + +ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้ด้วย เช่น: + +```js run no-beautify +let *!*userName*/!* = 'John'; + +function showMessage() { + let message = 'Hello, ' + *!*userName*/!*; + alert(message); +} + +showMessage(); // Hello, John +``` + +ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้อย่างเต็มที่ และยังสามารถแก้ไขค่าได้ด้วย + +ตัวอย่างเช่น: + +```js run +let *!*userName*/!* = 'John'; + +function showMessage() { + *!*userName*/!* = "Bob"; // (1) เปลี่ยนค่าตัวแปรภายนอก + + let message = 'Hello, ' + *!*userName*/!*; + alert(message); +} + +alert( userName ); // *!*John*/!* ก่อนเรียกฟังก์ชัน + +showMessage(); + +alert( userName ); // *!*Bob*/!*, ค่าถูกเปลี่ยนโดยฟังก์ชัน +``` + +ตัวแปรภายนอกจะถูกใช้ก็ต่อเมื่อไม่มีตัวแปรท้องถิ่นที่ชื่อเดียวกัน + +ถ้ามีการประกาศตัวแปรที่ชื่อซ้ำกันภายในฟังก์ชัน มันจะ *บดบัง* ตัวแปรภายนอก เช่น ในโค้ดด้านล่าง ฟังก์ชันจะใช้ `userName` ท้องถิ่นของตัวเอง ส่วนตัวภายนอกจะถูกมองข้าม: + +```js run +let userName = 'John'; + +function showMessage() { +*!* + let userName = "Bob"; // ประกาศตัวแปรท้องถิ่น +*/!* + + let message = 'Hello, ' + userName; // *!*Bob*/!* + alert(message); +} + +// ฟังก์ชันจะสร้างและใช้ userName ของตัวเอง +showMessage(); + +alert( userName ); // *!*John*/!*, ไม่เปลี่ยนแปลง เพราะฟังก์ชันไม่ได้เข้าถึงตัวแปรภายนอก +``` + +```smart header="ตัวแปรโกลบอล (Global variables)" +ตัวแปรที่ประกาศนอกฟังก์ชันใดๆ เช่น `userName` ภายนอกในตัวอย่างข้างต้น เรียกว่า *ตัวแปรโกลบอล* + +ตัวแปรโกลบอลจะมองเห็นได้จากทุกฟังก์ชัน (ยกเว้นถูกบดบังโดยตัวแปรท้องถิ่น) + +เป็นแนวทางปฏิบัติที่ดีที่จะลดการใช้ตัวแปรโกลบอล โค้ดสมัยใหม่มักมีตัวแปรโกลบอลน้อยมากหรือไม่มีเลย ตัวแปรส่วนใหญ่จะอยู่ภายในฟังก์ชันของตัวเอง อย่างไรก็ตาม บางครั้งตัวแปรโกลบอลก็มีประโยชน์ในการเก็บข้อมูลระดับโปรเจกต์ +``` \ No newline at end of file From 51b35caba1fe538a5f58280c4be61e6c60735514 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 22:09:49 +0700 Subject: [PATCH 03/10] Fix variable scoping in function basics --- 1-js/02-first-steps/15-function-basics/article.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index 89e237525..428dcd93d 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -105,9 +105,9 @@ showMessage(); alert( userName ); // *!*Bob*/!*, ค่าถูกเปลี่ยนโดยฟังก์ชัน ``` -ตัวแปรภายนอกจะถูกใช้ก็ต่อเมื่อไม่มีตัวแปรท้องถิ่นที่ชื่อเดียวกัน +ตัวแปรภายนอกจะถูกใช้ก็ต่อเมื่อไม่มีตัวแปรภายในฟังก์ชั่นที่ชื่อเดียวกัน -ถ้ามีการประกาศตัวแปรที่ชื่อซ้ำกันภายในฟังก์ชัน มันจะ *บดบัง* ตัวแปรภายนอก เช่น ในโค้ดด้านล่าง ฟังก์ชันจะใช้ `userName` ท้องถิ่นของตัวเอง ส่วนตัวภายนอกจะถูกมองข้าม: +ถ้ามีการประกาศตัวแปรที่ชื่อซ้ำกันภายในฟังก์ชัน มันจะ *บดบัง* ตัวแปรภายนอก เช่น ในโค้ดด้านล่าง ฟังก์ชันจะใช้ `userName` ภายในของตัวเอง ส่วนตัวภายนอกจะถูกมองข้าม: ```js run let userName = 'John'; @@ -130,7 +130,7 @@ alert( userName ); // *!*John*/!*, ไม่เปลี่ยนแปลง ```smart header="ตัวแปรโกลบอล (Global variables)" ตัวแปรที่ประกาศนอกฟังก์ชันใดๆ เช่น `userName` ภายนอกในตัวอย่างข้างต้น เรียกว่า *ตัวแปรโกลบอล* -ตัวแปรโกลบอลจะมองเห็นได้จากทุกฟังก์ชัน (ยกเว้นถูกบดบังโดยตัวแปรท้องถิ่น) +ตัวแปรโกลบอลจะมองเห็นได้จากทุกฟังก์ชัน (ยกเว้นถูกบดบังโดยตัวแปรภายในฟังก์ชั่น) เป็นแนวทางปฏิบัติที่ดีที่จะลดการใช้ตัวแปรโกลบอล โค้ดสมัยใหม่มักมีตัวแปรโกลบอลน้อยมากหรือไม่มีเลย ตัวแปรส่วนใหญ่จะอยู่ภายในฟังก์ชันของตัวเอง อย่างไรก็ตาม บางครั้งตัวแปรโกลบอลก็มีประโยชน์ในการเก็บข้อมูลระดับโปรเจกต์ ``` \ No newline at end of file From 5d2d4866fe8d3603aeff84985c93ad3e2b3cb5fa Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 22:16:03 +0700 Subject: [PATCH 04/10] =?UTF-8?q?=E0=B8=9E=E0=B8=B2=E0=B8=A3=E0=B8=B2?= =?UTF-8?q?=E0=B8=A1=E0=B8=B4=E0=B9=80=E0=B8=95=E0=B8=AD=E0=B8=A3=E0=B9=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../15-function-basics/article.md | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index 428dcd93d..b459fc190 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -133,4 +133,52 @@ alert( userName ); // *!*John*/!*, ไม่เปลี่ยนแปลง ตัวแปรโกลบอลจะมองเห็นได้จากทุกฟังก์ชัน (ยกเว้นถูกบดบังโดยตัวแปรภายในฟังก์ชั่น) เป็นแนวทางปฏิบัติที่ดีที่จะลดการใช้ตัวแปรโกลบอล โค้ดสมัยใหม่มักมีตัวแปรโกลบอลน้อยมากหรือไม่มีเลย ตัวแปรส่วนใหญ่จะอยู่ภายในฟังก์ชันของตัวเอง อย่างไรก็ตาม บางครั้งตัวแปรโกลบอลก็มีประโยชน์ในการเก็บข้อมูลระดับโปรเจกต์ -``` \ No newline at end of file +``` + +## พารามิเตอร์ (Parameters) + +เราสามารถส่งผ่านข้อมูลใดๆ ไปยังฟังก์ชันโดยใช้พารามิเตอร์ได้ + +ในตัวอย่างด้านล่าง ฟังก์ชันมีพารามิเตอร์สองตัวคือ `from` และ `text` + +```js run +function showMessage(*!*from, text*/!*) { // พารามิเตอร์: from, text + alert(from + ': ' + text); +} + +*!*showMessage('Ann', 'Hello!');*/!* // Ann: Hello! (*) +*!*showMessage('Ann', "What's up?");*/!* // Ann: What's up? (**) +``` + +เมื่อฟังก์ชันถูกเรียกในบรรทัด `(*)` และ `(**)` ค่าที่ส่งเข้าไปจะถูกคัดลอกไปยังตัวแปรท้องถิ่น `from` และ `text` จากนั้นฟังก์ชันก็จะใช้ตัวแปรเหล่านั้น + +นี่คืออีกตัวอย่าง: เรามีตัวแปร `from` และส่งผ่านมันเข้าไปในฟังก์ชัน สังเกตว่า ฟังก์ชันเปลี่ยนค่า `from` แต่การเปลี่ยนแปลงนั้นจะไม่ปรากฏภายนอก เพราะฟังก์ชันจะได้รับสำเนาของค่าเสมอ: + +```js run +function showMessage(from, text) { + +*!* + from = '*' + from + '*'; // ทำให้ "from" ดูสวยงามขึ้น +*/!* + + alert( from + ': ' + text ); +} + +let from = "Ann"; + +showMessage(from, "Hello"); // *Ann*: Hello + +// ค่าของ "from" ยังเหมือนเดิม ฟังก์ชันแก้ไขสำเนาในตัวเอง +alert( from ); // Ann +``` + +เมื่อค่าถูกส่งผ่านเข้าไปเป็นพารามิเตอร์ของฟังก์ชัน เราเรียกค่านั้นว่า *อาร์กิวเมนต์ (argument)* + +หรือพูดอีกอย่างคือ เพื่อให้เข้าใจคำศัพท์ชัดเจน: + +- พารามิเตอร์ คือตัวแปรที่ระบุในวงเล็บตอนประกาศฟังก์ชัน (เป็นคำศัพท์ช่วงประกาศ) +- อาร์กิวเมนต์ คือค่าที่ส่งผ่านเข้าไปในฟังก์ชันตอนเรียกใช้ (เป็นคำศัพท์ช่วงเรียกใช้) + +เราประกาศฟังก์ชันโดยระบุพารามิเตอร์ของมัน จากนั้นเรียกใช้มันโดยส่งผ่านอาร์กิวเมนต์เข้าไป + +ในตัวอย่างข้างบน เราอาจพูดว่า: "ฟังก์ชัน `showMessage` ถูกประกาศด้วยพารามิเตอร์สองตัว จากนั้นถูกเรียกใช้ด้วยอาร์กิวเมนต์สองตัวคือ `from` และ `"Hello"`" \ No newline at end of file From a9df01c222b93532798ccbf11282ed4b29b8a35f Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 22:22:10 +0700 Subject: [PATCH 05/10] =?UTF-8?q?=E0=B8=84=E0=B9=88=E0=B8=B2=E0=B9=80?= =?UTF-8?q?=E0=B8=A3=E0=B8=B4=E0=B9=88=E0=B8=A1=E0=B8=95=E0=B9=89=E0=B8=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../15-function-basics/article.md | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index b459fc190..d3c8cc6c4 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -181,4 +181,82 @@ alert( from ); // Ann เราประกาศฟังก์ชันโดยระบุพารามิเตอร์ของมัน จากนั้นเรียกใช้มันโดยส่งผ่านอาร์กิวเมนต์เข้าไป -ในตัวอย่างข้างบน เราอาจพูดว่า: "ฟังก์ชัน `showMessage` ถูกประกาศด้วยพารามิเตอร์สองตัว จากนั้นถูกเรียกใช้ด้วยอาร์กิวเมนต์สองตัวคือ `from` และ `"Hello"`" \ No newline at end of file +ในตัวอย่างข้างบน เราอาจพูดว่า: "ฟังก์ชัน `showMessage` ถูกประกาศด้วยพารามิเตอร์สองตัว จากนั้นถูกเรียกใช้ด้วยอาร์กิวเมนต์สองตัวคือ `from` และ `"Hello"`" + +## ค่าเริ่มต้น (Default values) + +หากฟังก์ชันถูกเรียกใช้แต่ไม่ได้ส่งอาร์กิวเมนต์มาด้วย ค่าที่สอดคล้องกันจะเป็น `undefined` + +ยกตัวอย่างเช่น ฟังก์ชัน `showMessage(from, text)` ที่กล่าวถึงก่อนหน้า สามารถเรียกใช้ด้วยอาร์กิวเมนต์เพียงตัวเดียวได้: + +```js +showMessage("Ann"); +``` + +นี่ไม่ใช่ข้อผิดพลาด การเรียกแบบนี้จะแสดงผลเป็น `"*Ann*: undefined"` เนื่องจากไม่ได้ส่งค่าให้กับพารามิเตอร์ `text` จึงมีค่าเป็น `undefined` + +เราสามารถระบุค่าที่เรียกว่า "ค่าเริ่มต้น" (ใช้เมื่อไม่ได้ส่งค่ามา) สำหรับพารามิเตอร์ในการประกาศฟังก์ชันได้ โดยใช้ `=`: + +```js run +function showMessage(from, *!*text = "no text given"*/!*) { + alert( from + ": " + text ); +} + +showMessage("Ann"); // Ann: no text given +``` + +ตอนนี้ถ้าไม่ได้ส่งพารามิเตอร์ `text` มา มันจะมีค่าเป็น `"no text given"` + +ค่าเริ่มต้นจะถูกนำมาใช้ด้วย ถ้าพารามิเตอร์มีอยู่แต่ค่าเป็น `undefined` อย่างเคร่งครัด เช่นนี้: + +```js +showMessage("Ann", undefined); // Ann: no text given +``` + +ในที่นี้ `"no text given"` เป็น string แต่มันสามารถเป็นนิพจน์ที่ซับซ้อนกว่านั้นได้ ซึ่งจะถูกประเมินค่าและกำหนดให้เฉพาะเมื่อไม่ได้ส่งพารามิเตอร์มาเท่านั้น ดังนั้นสิ่งนี้ก็เป็นไปได้: + +```js run +function showMessage(from, text = anotherFunction()) { + // anotherFunction() จะถูกเรียกใช้เฉพาะเมื่อไม่ได้ส่ง text มา + // ผลลัพธ์ของมันจะกลายเป็นค่าของ text +} +``` + +```smart header="การประเมินค่าพารามิเตอร์เริ่มต้น" +ใน JavaScript พารามิเตอร์เริ่มต้นจะถูกประเมินค่าทุกครั้งที่เรียกใช้ฟังก์ชันโดยไม่ส่งพารามิเตอร์ที่เกี่ยวข้อง + +ในตัวอย่างข้างต้น `anotherFunction()` จะไม่ถูกเรียกใช้เลย ถ้าส่งพารามิเตอร์ `text` มา + +ในทางกลับกัน มันจะถูกเรียกใช้แยกต่างหากทุกครั้งที่ไม่ได้ส่ง `text` มา +``` + +````smart header="พารามิเตอร์เริ่มต้นในโค้ด JavaScript เก่า" +เมื่อหลายปีก่อน JavaScript ไม่รองรับไวยากรณ์ของพารามิเตอร์เริ่มต้น ดังนั้นคนจึงใช้วิธีอื่นในการระบุค่าเริ่มต้น + +ปัจจุบันเราอาจพบเจอสิ่งเหล่านี้ในสคริปต์เก่าๆ + +เช่น การตรวจสอบ `undefined` อย่างชัดเจน: + +```js +function showMessage(from, text) { +*!* + if (text === undefined) { + text = 'no text given'; + } +*/!* + + alert( from + ": " + text ); +} +``` + +...หรือใช้ตัวดำเนินการ `||`: + +```js +function showMessage(from, text) { + // ถ้าค่าของ text เป็น falsy ให้กำหนดค่าเริ่มต้น + // ซึ่งสมมติว่า text == "" เหมือนกับไม่มี text เลย + text = text || 'no text given'; + ... +} +``` +```` \ No newline at end of file From aa1aedb9a9b63e65a5dc1ffcefaa38215644dbff Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 22:25:32 +0700 Subject: [PATCH 06/10] =?UTF-8?q?=E0=B8=9E=E0=B8=B2=E0=B8=A3=E0=B8=B2?= =?UTF-8?q?=E0=B8=A1=E0=B8=B4=E0=B9=80=E0=B8=95=E0=B8=AD=E0=B8=A3=E0=B9=8C?= =?UTF-8?q?=E0=B9=80=E0=B8=A3=E0=B8=B4=E0=B9=88=E0=B8=A1=E0=B8=95=E0=B9=89?= =?UTF-8?q?=E0=B8=99=E0=B8=97=E0=B8=B2=E0=B8=87=E0=B9=80=E0=B8=A5=E0=B8=B7?= =?UTF-8?q?=E0=B8=AD=E0=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../15-function-basics/article.md | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index d3c8cc6c4..dcdc8d815 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -259,4 +259,49 @@ function showMessage(from, text) { ... } ``` -```` \ No newline at end of file +```` + +### พารามิเตอร์เริ่มต้นทางเลือก + +บางครั้งการกำหนดค่าเริ่มต้นให้พารามิเตอร์ในภายหลัง หลังจากประกาศฟังก์ชันไปแล้ว ก็มีเหตุผลเช่นกัน + +เราสามารถตรวจสอบว่ามีการส่งพารามิเตอร์มาหรือไม่ระหว่างการทำงานของฟังก์ชัน โดยเปรียบเทียบกับ `undefined`: + +```js run +function showMessage(text) { + // ... + +*!* + if (text === undefined) { // ถ้าไม่มีพารามิเตอร์ส่งมา + text = 'ข้อความว่าง'; + } +*/!* + + alert(text); +} + +showMessage(); // ข้อความว่าง +``` + +...หรือเราสามารถใช้ตัวดำเนินการ `||`: + +```js +function showMessage(text) { + // ถ้า text เป็น undefined หรือ falsy อื่นๆ ให้กำหนดเป็น 'empty' + text = text || 'empty'; + ... +} +``` + +JavaScript เอนจินสมัยใหม่รองรับ[ตัวดำเนินการรวม nullish](info:nullish-coalescing-operator) `??` ซึ่งจะเหมาะกว่าเมื่อต้องการให้ค่า falsy ส่วนใหญ่ เช่น `0` ถือเป็นค่า "ปกติ": + +```js run +function showCount(count) { + // ถ้า count เป็น undefined หรือ null ให้แสดง "unknown" + alert(count ?? "unknown"); +} + +showCount(0); // 0 +showCount(null); // unknown +showCount(); // unknown +``` \ No newline at end of file From c06a5da0284883cb5d59ba38f8ce62d78206d5ba Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 22:31:04 +0700 Subject: [PATCH 07/10] =?UTF-8?q?=E0=B8=81=E0=B8=B2=E0=B8=A3=E0=B8=AA?= =?UTF-8?q?=E0=B9=88=E0=B8=87=E0=B8=84=E0=B8=B7=E0=B8=99=E0=B8=84=E0=B9=88?= =?UTF-8?q?=E0=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../15-function-basics/article.md | 111 +++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index dcdc8d815..164cadf9c 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -304,4 +304,113 @@ function showCount(count) { showCount(0); // 0 showCount(null); // unknown showCount(); // unknown -``` \ No newline at end of file +``` + +## การส่งคืนค่า (Returning a value) + +ฟังก์ชันสามารถส่งคืนค่ากลับไปยังโค้ดที่เรียกใช้เป็นผลลัพธ์ได้ + +ตัวอย่างง่ายๆ คือฟังก์ชันที่รวมผลบวกของสองค่า: + +```js run no-beautify +function sum(a, b) { + *!*return*/!* a + b; +} + +let result = sum(1, 2); +alert( result ); // 3 +``` + +คำสั่ง `return` สามารถอยู่ที่ไหนก็ได้ในฟังก์ชัน เมื่อการทำงานมาถึงมัน ฟังก์ชันจะหยุดและส่งคืนค่าไปยังโค้ดที่เรียกใช้ (กำหนดให้กับ `result` ในตัวอย่างข้างต้น) + +ในฟังก์ชันเดียวอาจมีหลายจุดที่ใช้ `return` ได้ เช่น: + +```js run +function checkAge(age) { + if (age >= 18) { +*!* + return true; +*/!* + } else { +*!* + return confirm('คุณได้รับอนุญาตจากผู้ปกครองหรือไม่?'); +*/!* + } +} + +let age = prompt('คุณอายุเท่าไหร่?', 18); + +if ( checkAge(age) ) { + alert('อนุญาตให้เข้าใช้งาน'); +} else { + alert('ไม่อนุญาตให้เข้าใช้งาน'); +} +``` + +เราสามารถใช้ `return` โดยไม่มีค่าก็ได้ ซึ่งจะทำให้ฟังก์ชันจบการทำงานทันที + +ตัวอย่างเช่น: + +```js +function showMovie(age) { + if ( !checkAge(age) ) { +*!* + return; +*/!* + } + + alert("กำลังแสดงภาพยนตร์ให้ชม"); // (*) + // ... +} +``` + +ในโค้ดข้างต้น ถ้า `checkAge(age)` คืนค่า `false` ฟังก์ชัน `showMovie` จะไม่ทำงานต่อไปที่ `alert` + +````smart header="ฟังก์ชันที่มี `return` ว่างหรือไม่มี `return` จะคืนค่า `undefined`" +ถ้าฟังก์ชันไม่มีการคืนค่า มันจะเหมือนกับการคืนค่า `undefined`: + +```js run +function doNothing() { /* ว่าง */ } + +alert( doNothing() === undefined ); // true +``` + +`return` ว่างก็เหมือนกับ `return undefined`: + +```js run +function doNothing() { + return; +} + +alert( doNothing() === undefined ); // true +``` +```` + +````warn header="อย่าขึ้นบรรทัดใหม่ระหว่าง `return` กับค่าที่คืน" +สำหรับนิพจน์ยาวๆ ใน `return` อาจเย้ายวนใจให้แยกเป็นบรรทัดใหม่ แบบนี้: + +```js +return + (some + long + expression + or + whatever * f(a) + f(b)) +``` +นั่นจะไม่ทำงาน เพราะ JavaScript จะสันนิษฐานว่ามีเครื่องหมายอัฒภาคหลัง `return` ซึ่งจะทำงานเหมือนกับ: + +```js +return*!*;*/!* + (some + long + expression + or + whatever * f(a) + f(b)) +``` + +ดังนั้นมันจะกลายเป็น return เปล่าๆ อย่างมีประสิทธิภาพ + +ถ้าเราต้องการให้นิพจน์ที่คืนค่าขึ้นบรรทัดใหม่ เราควรเริ่มต้นในบรรทัดเดียวกับ `return` หรืออย่างน้อยควรใส่วงเล็บเปิดเอาไว้ที่นั่น แบบนี้: + +```js +return ( + some + long + expression + + or + + whatever * f(a) + f(b) + ) +``` + +และมันจะทำงานตามที่เราคาดหวัง +```` \ No newline at end of file From 1815c3c92d5ae9748dde8f1551cae339daf6e52e Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 23:24:36 +0700 Subject: [PATCH 08/10] =?UTF-8?q?=E0=B8=81=E0=B8=B2=E0=B8=A3=E0=B8=95?= =?UTF-8?q?=E0=B8=B1=E0=B9=89=E0=B8=87=E0=B8=8A=E0=B8=B7=E0=B9=88=E0=B8=AD?= =?UTF-8?q?=E0=B8=9F=E0=B8=B1=E0=B8=87=E0=B8=81=E0=B9=8C=E0=B8=8A=E0=B8=B1?= =?UTF-8?q?=E0=B8=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../15-function-basics/article.md | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index 164cadf9c..013a78835 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -413,4 +413,53 @@ return ( ``` และมันจะทำงานตามที่เราคาดหวัง -```` \ No newline at end of file +```` + +## การตั้งชื่อฟังก์ชัน [#function-naming] + +ฟังก์ชันคือการกระทำ ดังนั้นชื่อของมันมักจะเป็นคำกริยา ชื่อควรสั้นกระชับ ตรงประเด็นที่สุดเท่าที่จะเป็นไปได้ และบ่งบอกว่าฟังก์ชันทำอะไร เพื่อให้คนที่อ่านโค้ดเข้าใจได้ทันทีว่าฟังก์ชันนั้นทำหน้าที่อะไร + +เป็นแนวปฏิบัติที่แพร่หลายในการขึ้นต้นชื่อฟังก์ชันด้วยคำกริยาเพื่ออธิบายการกระทำคร่าวๆ ทีมงานควรตกลงกันเรื่องความหมายของคำนำหน้าเหล่านี้ให้ชัดเจน + +ตัวอย่างเช่น ฟังก์ชันที่ขึ้นต้นด้วย `"show"` มักจะแสดงบางอย่าง + +ฟังก์ชันที่ขึ้นต้นด้วย... + +- `"get…"` -- คืนค่าบางอย่าง +- `"calc…"` -- คำนวณบางอย่าง +- `"create…"` -- สร้างบางอย่าง +- `"check…"` -- ตรวจสอบบางอย่างและคืนค่าบูลีน ฯลฯ + +ตัวอย่างชื่อฟังก์ชันเหล่านี้: + +```js no-beautify +showMessage(..) // แสดงข้อความ +getAge(..) // คืนค่าอายุ (ได้ค่ามาด้วยวิธีใดวิธีหนึ่ง) +calcSum(..) // คำนวณผลรวมและคืนผลลัพธ์ +createForm(..) // สร้างฟอร์ม (และมักจะคืนค่าฟอร์มนั้น) +checkPermission(..) // ตรวจสอบสิทธิ์ คืนค่า true/false +``` + +เมื่อใช้คำนำหน้าแล้ว เพียงแค่มองชื่อฟังก์ชันก็พอจะเข้าใจได้ว่ามันทำงานแบบไหนและคืนค่าประเภทใด + +```smart header="หนึ่งฟังก์ชัน -- หนึ่งการกระทำ" +ฟังก์ชันควรทำในสิ่งที่ชื่อของมันบอกไว้ ไม่มากไปกว่านั้น + +การกระทำสองอย่างที่เป็นอิสระจากกัน มักสมควรแยกเป็นสองฟังก์ชัน แม้ว่าปกติจะถูกเรียกใช้ด้วยกัน (ในกรณีนั้นเราอาจสร้างฟังก์ชันที่สามเพื่อเรียกใช้ทั้งสองฟังก์ชันนั้น) + +ตัวอย่างที่ละเมิดกฎข้อนี้: + +- `getAge` -- จะไม่ดีถ้ามันแสดง `alert` บอกอายุด้วย (ควรแค่ดึงค่าอายุเท่านั้น) +- `createForm` -- จะไม่ดีถ้ามันแก้ไขเอกสารด้วยการเพิ่มฟอร์มเข้าไป (ควรแค่สร้างฟอร์มและคืนค่า) +- `checkPermission` -- จะไม่ดีถ้ามันแสดงข้อความ `อนุญาต/ไม่อนุญาตให้เข้าถึง` (ควรแค่ตรวจสอบและคืนผลลัพธ์) + +ตัวอย่างเหล่านี้สมมติความหมายทั่วไปของคำนำหน้า คุณและทีมสามารถตกลงกันถึงความหมายอื่นๆ ได้ แต่โดยปกติมักจะไม่ค่อยแตกต่างกันมาก ไม่ว่าอย่างไร คุณควรเข้าใจชัดเจนว่าคำนำหน้าหมายถึงอะไร ฟังก์ชันที่มีคำนำหน้าสามารถและไม่ควรทำอะไรได้บ้าง ฟังก์ชันที่มีคำนำหน้าเดียวกันทั้งหมดควรปฏิบัติตามกฎเดียวกัน และทีมควรแบ่งปันความรู้นี้ร่วมกัน +``` + +```smart header="ชื่อฟังก์ชันที่สั้นมากๆ" +ฟังก์ชันที่ถูกใช้ *บ่อยมากๆ* บางครั้งอาจมีชื่อที่สั้นมากๆ + +เช่น เฟรมเวิร์ค [jQuery](https://jquery.com/) กำหนดฟังก์ชันชื่อ `$` ส่วนไลบรารี [Lodash](https://lodash.com/) มีฟังก์ชันหลักชื่อ `_` + +แต่สิ่งเหล่านี้เป็นข้อยกเว้น โดยทั่วไปแล้วชื่อฟังก์ชันควรกระชับและบ่งบอกความหมายได้ชัดเจน +``` \ No newline at end of file From 69cf4ae27e039789cc607289dd42c69ffbd52ad7 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 23:34:56 +0700 Subject: [PATCH 09/10] =?UTF-8?q?=E0=B8=9F=E0=B8=B1=E0=B8=87=E0=B8=81?= =?UTF-8?q?=E0=B9=8C=E0=B8=8A=E0=B8=B1=E0=B8=99=20=3D=3D=20=E0=B8=84?= =?UTF-8?q?=E0=B8=AD=E0=B8=A1=E0=B9=80=E0=B8=A1=E0=B8=99=E0=B8=95=E0=B9=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../15-function-basics/article.md | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index 013a78835..fe14b3514 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -462,4 +462,77 @@ checkPermission(..) // ตรวจสอบสิทธิ์ คืนค่ เช่น เฟรมเวิร์ค [jQuery](https://jquery.com/) กำหนดฟังก์ชันชื่อ `$` ส่วนไลบรารี [Lodash](https://lodash.com/) มีฟังก์ชันหลักชื่อ `_` แต่สิ่งเหล่านี้เป็นข้อยกเว้น โดยทั่วไปแล้วชื่อฟังก์ชันควรกระชับและบ่งบอกความหมายได้ชัดเจน -``` \ No newline at end of file +``` + +## ฟังก์ชัน == คอมเมนต์ + +ฟังก์ชันควรสั้นและทำเพียงหนึ่งสิ่งอย่างชัดเจน ถ้าสิ่งนั้นใหญ่เกินไป อาจคุ้มค่าที่จะแยกฟังก์ชันออกเป็นฟังก์ชันเล็กๆ สองสามอัน บางครั้งอาจไม่ง่ายนักที่จะทำตามกฎนี้ แต่มันเป็นสิ่งที่ดีอย่างแน่นอน + +ฟังก์ชันที่แยกออกมา นอกจากจะทดสอบและดีบักได้ง่ายกว่าแล้ว การมีอยู่ของมันยังเป็นคอมเมนต์ที่ดีเยี่ยมอีกด้วย! + +ยกตัวอย่างเช่น เปรียบเทียบฟังก์ชัน `showPrimes(n)` สองอันด้านล่าง แต่ละอันแสดงผล [จำนวนเฉพาะ](https://en.wikipedia.org/wiki/Prime_number) จนถึง `n` + +แบบแรกใช้ label: + +```js +function showPrimes(n) { + nextPrime: for (let i = 2; i < n; i++) { + + for (let j = 2; j < i; j++) { + if (i % j == 0) continue nextPrime; + } + + alert( i ); // จำนวนเฉพาะ + } +} +``` + +แบบที่สองใช้ฟังก์ชันเสริม `isPrime(n)` เพื่อตรวจสอบว่าเป็นจำนวนเฉพาะหรือไม่: + +```js +function showPrimes(n) { + + for (let i = 2; i < n; i++) { + *!*if (!isPrime(i)) continue;*/!* + + alert(i); // จำนวนเฉพาะ + } +} + +function isPrime(n) { + for (let i = 2; i < n; i++) { + if ( n % i == 0) return false; + } + return true; +} +``` + +แบบที่สองเข้าใจง่ายกว่าใช่ไหม? แทนที่จะเห็นส่วนโค้ด เราเห็นชื่อการกระทำ (`isPrime`) บางครั้งผู้คนเรียกโค้ดแบบนี้ว่า *อธิบายตัวเอง* + +ดังนั้นเราสามารถสร้างฟังก์ชันได้แม้ไม่ได้ตั้งใจจะนำมาใช้ซ้ำ มันจัดโครงสร้างโค้ดและทำให้อ่านง่ายขึ้น + +## สรุป + +การประกาศฟังก์ชันมีหน้าตาแบบนี้: + +```js +function name(parameters, delimited, by, comma) { + /* code */ +} +``` + +- ค่าที่ส่งเข้าไปในฟังก์ชันผ่านพารามิเตอร์จะถูกคัดลอกไปเป็นตัวแปรท้องถิ่น +- ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้ แต่มันจะทำงานจากด้านในออกไปด้านนอกเท่านั้น โค้ดภายนอกฟังก์ชันจะไม่เห็นตัวแปรท้องถิ่นของมัน +- ฟังก์ชันสามารถคืนค่าได้ ถ้าไม่คืนค่า ผลลัพธ์จะเป็น `undefined` + +เพื่อให้โค้ดสะอาดและเข้าใจง่าย แนะนำให้ใช้ตัวแปรท้องถิ่นและพารามิเตอร์ในฟังก์ชันเป็นหลัก ไม่ใช้ตัวแปรภายนอก + +การทำความเข้าใจฟังก์ชันที่รับพารามิเตอร์ ทำงานกับมัน และคืนผลลัพธ์จะง่ายกว่าฟังก์ชันที่ไม่รับพารามิเตอร์แต่ไปแก้ไขตัวแปรภายนอก ซึ่งถือเป็นผลข้างเคียง + +การตั้งชื่อฟังก์ชัน: + +- ชื่อควรบอกชัดเจนว่าฟังก์ชันทำอะไร เมื่อเห็นการเรียกฟังก์ชันในโค้ด ชื่อที่ดีจะให้ความเข้าใจในทันทีว่ามันทำอะไรและคืนค่าอะไร +- ฟังก์ชันคือการกระทำ ดังนั้นชื่อฟังก์ชันมักเป็นคำกริยา +- มีคำนำหน้าฟังก์ชันที่ใช้กันแพร่หลายเช่น `create…`, `show…`, `get…`, `check…` เป็นต้น ให้ใช้เป็นตัวบอกใบ้ว่าฟังก์ชันทำอะไร + +ฟังก์ชันเป็นบล็อกสำคัญในการสร้างสคริปต์ ตอนนี้เราได้เรียนรู้พื้นฐานแล้ว เราจึงสามารถเริ่มสร้างและใช้มันได้จริงๆ แต่นี่เป็นเพียงจุดเริ่มต้นของเส้นทาง เรายังจะกลับมาที่ฟังก์ชันอีกหลายครั้งเพื่อศึกษาฟีเจอร์ขั้นสูงต่างๆ ให้ลึกซึ้งยิ่งขึ้น \ No newline at end of file From d58b9a3391320c46d4d3676ba0202e9c305131d0 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Sun, 31 Mar 2024 23:37:12 +0700 Subject: [PATCH 10/10] Refactor function variable names --- 1-js/02-first-steps/15-function-basics/article.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index fe14b3514..abbbaf854 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -58,7 +58,7 @@ showMessage(); ```js run function showMessage() { *!* - let message = "Hello, I'm JavaScript!"; // ตัวแปรท้องถิ่น + let message = "Hello, I'm JavaScript!"; // ตัวแปรภายในฟังก์ชัน */!* alert( message ); @@ -114,7 +114,7 @@ let userName = 'John'; function showMessage() { *!* - let userName = "Bob"; // ประกาศตัวแปรท้องถิ่น + let userName = "Bob"; // ประกาศตัวแปรภายในฟังก์ชัน */!* let message = 'Hello, ' + userName; // *!*Bob*/!* @@ -150,7 +150,7 @@ function showMessage(*!*from, text*/!*) { // พารามิเตอร์: *!*showMessage('Ann', "What's up?");*/!* // Ann: What's up? (**) ``` -เมื่อฟังก์ชันถูกเรียกในบรรทัด `(*)` และ `(**)` ค่าที่ส่งเข้าไปจะถูกคัดลอกไปยังตัวแปรท้องถิ่น `from` และ `text` จากนั้นฟังก์ชันก็จะใช้ตัวแปรเหล่านั้น +เมื่อฟังก์ชันถูกเรียกในบรรทัด `(*)` และ `(**)` ค่าที่ส่งเข้าไปจะถูกคัดลอกไปยังตัวแปรภายในฟังก์ชั่น `from` และ `text` จากนั้นฟังก์ชันก็จะใช้ตัวแปรเหล่านั้น นี่คืออีกตัวอย่าง: เรามีตัวแปร `from` และส่งผ่านมันเข้าไปในฟังก์ชัน สังเกตว่า ฟังก์ชันเปลี่ยนค่า `from` แต่การเปลี่ยนแปลงนั้นจะไม่ปรากฏภายนอก เพราะฟังก์ชันจะได้รับสำเนาของค่าเสมอ: @@ -521,11 +521,11 @@ function name(parameters, delimited, by, comma) { } ``` -- ค่าที่ส่งเข้าไปในฟังก์ชันผ่านพารามิเตอร์จะถูกคัดลอกไปเป็นตัวแปรท้องถิ่น -- ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้ แต่มันจะทำงานจากด้านในออกไปด้านนอกเท่านั้น โค้ดภายนอกฟังก์ชันจะไม่เห็นตัวแปรท้องถิ่นของมัน +- ค่าที่ส่งเข้าไปในฟังก์ชันผ่านพารามิเตอร์จะถูกคัดลอกไปเป็นตัวแปรภายในฟังก์ชั่น +- ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้ แต่มันจะทำงานจากด้านในออกไปด้านนอกเท่านั้น โค้ดภายนอกฟังก์ชันจะไม่เห็นตัวแปรภายในฟังก์ชั่นของมัน - ฟังก์ชันสามารถคืนค่าได้ ถ้าไม่คืนค่า ผลลัพธ์จะเป็น `undefined` -เพื่อให้โค้ดสะอาดและเข้าใจง่าย แนะนำให้ใช้ตัวแปรท้องถิ่นและพารามิเตอร์ในฟังก์ชันเป็นหลัก ไม่ใช้ตัวแปรภายนอก +เพื่อให้โค้ดสะอาดและเข้าใจง่าย แนะนำให้ใช้ตัวแปรภายในฟังก์ชั่นและพารามิเตอร์ในฟังก์ชันเป็นหลัก ไม่ใช้ตัวแปรภายนอก การทำความเข้าใจฟังก์ชันที่รับพารามิเตอร์ ทำงานกับมัน และคืนผลลัพธ์จะง่ายกว่าฟังก์ชันที่ไม่รับพารามิเตอร์แต่ไปแก้ไขตัวแปรภายนอก ซึ่งถือเป็นผลข้างเคียง