diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index 2f4f518f3..13e8486ff 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -1,72 +1,99 @@ -# An Introduction to JavaScript +# บทนำสู่ JavaScript -Let's see what's so special about JavaScript, what we can achieve with it, and what other technologies play well with it. +มาดูกันว่า JavaScript มีลักษณะพิเศษอะไรบ้าง เราสามารถทำอะไรได้ด้วยภาษานี้ และมันเข้ากันได้ดีกับเทคโนโลยีใดบ้าง -## What is JavaScript? +## JavaScript คืออะไร? -*JavaScript* was initially created to "make web pages alive". +*JavaScript* ถูกสร้างขึ้นเพื่อ "ทำให้เว็บเพจมีชีวิตชีวา" -The programs in this language are called *scripts*. They can be written right in a web page's HTML and run automatically as the page loads. +โปรแกรมที่เขียนด้วยภาษานี้เรียกว่า *สคริปต์* ซึ่งสามารถแทรกลงในโค้ด HTML ของเว็บเพจได้โดยตรง และทำงานโดยอัตโนมัติเมื่อเพจนั้นโหลดขึ้นมา -Scripts are provided and executed as plain text. They don't need special preparation or compilation to run. +สคริปต์จะถูกเตรียมและประมวลผลในรูปแบบข้อความธรรมดา ไม่จำเป็นต้องมีขั้นตอนการเตรียมหรือคอมไพล์พิเศษใดๆ ก่อนการทำงาน -In this aspect, JavaScript is very different from another language called [Java](https://en.wikipedia.org/wiki/Java_(programming_language)). +ในแง่นี้ JavaScript แตกต่างจากภาษา [Java](https://en.wikipedia.org/wiki/Java_(programming_language)) อย่างชัดเจน -```smart header="Why is it called JavaScript?" -When JavaScript was created, it initially had another name: "LiveScript". But Java was very popular at that time, so it was decided that positioning a new language as a "younger brother" of Java would help. +```smart header="ทำไมถึงมีชื่อว่า JavaScript?" +เมื่อ JavaScript ถูกสร้างขึ้นในยุคแรก มันมีชื่อว่า "LiveScript" แต่เนื่องจากในขณะนั้น Java กำลังได้รับความนิยมอย่างสูง จึงมีการตัดสินใจว่าการนำเสนอภาษาใหม่นี้ในฐานะ "น้องชาย" ของ Java จะช่วยให้เป็นที่สนใจมากขึ้น -But as it evolved, JavaScript became a fully independent language with its own specification called [ECMAScript](http://en.wikipedia.org/wiki/ECMAScript), and now it has no relation to Java at all. +แต่เมื่อมันค่อยๆ พัฒนาไป ในที่สุด JavaScript ก็กลายเป็นภาษาที่มีเอกลักษณ์เฉพาะตัวอย่างสมบูรณ์ มีมาตรฐานของตัวเองที่เรียกว่า [ECMAScript](http://en.wikipedia.org/wiki/ECMAScript) และปัจจุบันไม่มีความเกี่ยวข้องใดๆ กับ Java อีกต่อไป ``` -Today, JavaScript can execute not only in the browser, but also on the server, or actually on any device that has a special program called [the JavaScript engine](https://en.wikipedia.org/wiki/JavaScript_engine). +ในยุคปัจจุบัน JavaScript สามารถทำงานได้ไม่เพียงแค่ในเบราว์เซอร์ แต่ยังรันได้บนเซิร์ฟเวอร์หรืออุปกรณ์ใดๆ ที่มีโปรแกรมพิเศษที่เรียกว่า [the JavaScript engine](https://en.wikipedia.org/wiki/JavaScript_engine) -The browser has an embedded engine sometimes called a "JavaScript virtual machine". +เบราว์เซอร์แต่ละตัวมี engine ของตัวเองฝังอยู่ในตัว บางครั้งเรียกว่า "JavaScript virtual machine" -Different engines have different "codenames". For example: +Engine แต่ละตัวมีชื่อเรียก (codename) ที่แตกต่างกัน เช่น: -- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- in Chrome, Opera and Edge. -- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- in Firefox. -- ...There are other codenames like "Chakra" for IE, "JavaScriptCore", "Nitro" and "SquirrelFish" for Safari, etc. +- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- ใน Chrome, Opera และ Edge +- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- ใน Firefox +- ...มีชื่อเรียกอื่นๆ อีก เช่น "Chakra" ใน IE, "JavaScriptCore", "Nitro" และ "SquirrelFish" ใน Safari เป็นต้น -The terms above are good to remember because they are used in developer articles on the internet. We'll use them too. For instance, if "a feature X is supported by V8", then it probably works in Chrome, Opera and Edge. +จำคำศัพท์เหล่านี้ไว้จะเป็นประโยชน์ เพราะมักจะถูกกล่าวถึงในบทความสำหรับนักพัฒนาบ่อยๆ เราก็จะใช้มันเช่นกัน ตัวอย่างเช่น ถ้ามีการพูดว่า "ฟีเจอร์ X รองรับโดย V8" ซึ่งหมายความว่ามันน่าจะทำงานได้ใน Chrome, Opera และ Edge -```smart header="How do engines work?" +```smart header="engine ทำงานอย่างไร?" -Engines are complicated. But the basics are easy. +Engine มีกระบวนการทำงานที่ค่อนข้างซับซ้อน แต่พื้นฐานแล้วไม่ยาก +<<<<<<< HEAD +1. Engine (ที่ฝังมากับเบราว์เซอร์) อ่าน ("parse") สคริปต์ +2. แล้วแปลง ("compile") สคริปต์ให้เป็นภาษาเครื่อง +3. จากนั้นก็รันโค้ดภาษาเครื่องได้อย่างรวดเร็ว +======= 1. The engine (embedded if it's a browser) reads ("parses") the script. 2. Then it converts ("compiles") the script to machine code. 3. And then the machine code runs, pretty fast. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -The engine applies optimizations at each step of the process. It even watches the compiled script as it runs, analyzes the data that flows through it, and further optimizes the machine code based on that knowledge. +Engine จะใช้เทคนิคการปรับแต่งในทุกขั้นตอน มันจะติดตามข้อมูลของสคริปต์ที่ผ่านการคอมไพล์แล้ว วิเคราะห์การไหลของข้อมูล และใช้ข้อมูลที่ได้จากการวิเคราะห์นั้นมาปรับแต่งรหัสภาษาเครื่องให้ดีขึ้นไปอีก ``` -## What can in-browser JavaScript do? +## JavaScript ในเบราว์เซอร์ทำอะไรได้บ้าง? +<<<<<<< HEAD +JavaScript สมัยใหม่เป็นภาษาโปรแกรมที่ "ปลอดภัย" มันไม่สามารถเข้าถึงระดับล่างของหน่วยความจำหรือซีพียูได้โดยตรง เพราะถูกออกแบบมาเพื่อใช้งานในเบราว์เซอร์ที่ไม่จำเป็นต้องใช้ฟีเจอร์เหล่านั้น +======= Modern JavaScript is a "safe" programming language. It does not provide low-level access to memory or the CPU, because it was initially created for browsers which do not require it. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -JavaScript's capabilities greatly depend on the environment it's running in. For instance, [Node.js](https://wikipedia.org/wiki/Node.js) supports functions that allow JavaScript to read/write arbitrary files, perform network requests, etc. +ความสามารถของ JavaScript นั้นขึ้นอยู่กับสภาพแวดล้อมที่มันทำงานอยู่เป็นอย่างมาก เช่น [Node.js](https://wikipedia.org/wiki/Node.js) ช่วยเสริมความสามารถให้ JavaScript สามารถอ่านหรือเขียนแฟ้มใดๆ ก็ได้ ส่งคำขอผ่านเน็ตเวิร์ค เป็นต้น -In-browser JavaScript can do everything related to webpage manipulation, interaction with the user, and the webserver. +ส่วน JavaScript ในเบราว์เซอร์นั้น สามารถทำอะไรก็ตามที่เกี่ยวข้องกับการจัดการเว็บเพจ การโต้ตอบกับผู้ใช้ และเว็บเซิร์ฟเวอร์ -For instance, in-browser JavaScript is able to: +ตัวอย่างเช่น JavaScript ในเบราว์เซอร์สามารถ: -- Add new HTML to the page, change the existing content, modify styles. -- React to user actions, run on mouse clicks, pointer movements, key presses. -- Send requests over the network to remote servers, download and upload files (so-called [AJAX](https://en.wikipedia.org/wiki/Ajax_(programming)) and [COMET](https://en.wikipedia.org/wiki/Comet_(programming)) technologies). -- Get and set cookies, ask questions to the visitor, show messages. -- Remember the data on the client-side ("local storage"). +- เพิ่ม HTML ใหม่ลงในหน้าเว็บ เปลี่ยนแปลงเนื้อหาที่มีอยู่ แก้ไขรูปแบบ (style) ของหน้าเว็บ +- ตอบสนองต่อการกระทำของผู้ใช้ เช่นการคลิกเมาส์ การเลื่อนเคอร์เซอร์ และการกดปุ่ม +- ส่งคำขอไปยังเซิร์ฟเวอร์ผ่านเครือข่าย ดาวน์โหลดและอัปโหลดไฟล์ (เรียกกันว่า [AJAX](https://en.wikipedia.org/wiki/Ajax_(programming)) และ [COMET](https://en.wikipedia.org/wiki/Comet_(programming))) +- รับและตั้งค่าคุกกี้ ถามคำถามผู้ใช้ แสดงข้อความ +- จำข้อมูลฝั่งไคลเอนต์ ("local storage") -## What CAN'T in-browser JavaScript do? +## JavaScript ในเบราว์เซอร์ทำอะไรไม่ได้บ้าง? +<<<<<<< HEAD +ความสามารถของ JavaScript ในเบราว์เซอร์มีข้อจำกัดเพื่อความปลอดภัยของผู้ใช้ มีจุดประสงค์เพื่อป้องกันหน้าเว็บที่ไม่น่าไว้วางใจจากการเข้าถึงข้อมูลส่วนตัว หรือทำให้ข้อมูลของผู้ใช้เสียหาย +======= JavaScript's abilities in the browser are limited to protect the user's safety. The aim is to prevent an evil webpage from accessing private information or harming the user's data. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Examples of such restrictions include: +ตัวอย่างของข้อจำกัดเหล่านั้น ได้แก่: -- JavaScript on a webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS functions. +- JavaScript ในหน้าเว็บไม่สามารถอ่าน/เขียน/คัดลอกไฟล์ในฮาร์ดดิสก์ หรือเรียกใช้โปรแกรมอื่นๆ ได้โดยตรง มันไม่มีสิทธิ์เข้าถึงฟังก์ชันระบบของระบบปฏิบัติการเองโดยตรง - Modern browsers allow it to work with files, but the access is limited and only provided if the user does certain actions, like "dropping" a file into a browser window or selecting it via an `` tag. + เบราว์เซอร์รุ่นใหม่ๆ อนุญาตให้มันทำงานกับไฟล์ได้บ้าง แต่การเข้าถึงนั้นจะถูกจำกัดมากและต้องได้รับการยินยอมจากผู้ใช้ เช่นการ "ลาก" ไฟล์ลงในหน้าเว็บ หรือเลือกผ่านแท็ก `` +<<<<<<< HEAD + มีวิธีโต้ตอบกับกล้อง ไมโครโฟน และอุปกรณ์อื่นๆ ได้ แต่ต้องได้รับอนุญาตอย่างชัดเจนจากผู้ใช้เสมอ เพราะฉะนั้นหน้าเว็บที่ใช้ JavaScript จะไม่สามารถเปิดเว็บแคมแอบดูโดยไม่ให้ผู้ใช้สังเกตเห็นและส่งข้อมูลไปยัง [NSA](https://en.wikipedia.org/wiki/National_Security_Agency) ได้ +- แท็บ/วินโดว์ที่แตกต่างกันโดยปกติแล้วไม่รู้จักกัน แม้ในบางครั้งที่อาจทำได้ เช่นเมื่อหน้าต่างหนึ่งใช้ JavaScript เปิดหน้าต่างอื่นขึ้นมา แต่แม้ในกรณีนี้ JavaScript จากหน้าหนึ่งก็ไม่สามารถเข้าถึงหน้าอื่นได้หาก URL ของหน้านั้นมาจากโดเมน โปรโตคอล หรือพอร์ตที่ต่างกัน เรียกว่า "Same Origin Policy" + + สิ่งนี้จำเป็นต้องทำเพื่อให้มีการยินยอมและทำความเข้าใจ *ระหว่างหน้าเว็บทั้งสองฝ่าย* ในการแลกเปลี่ยนข้อมูล และต้องใช้โค้ด JavaScript พิเศษเพื่อจัดการเรื่องนี้ เราจะกล่าวถึงเรื่องนี้ในบทเรียนข้างหน้า + + ข้อจำกัดนี้ก็เพื่อความปลอดภัยของผู้ใช้ด้วยเช่นกัน ไม่ควรให้หน้า `http://anysite.com` ที่เปิดอยู่ในแท็บหนึ่ง สามารถเข้าถึง URL `http://gmail.com` ในอีกแท็บของเบราว์เซอร์ ซึ่งอาจจะขโมยข้อมูลจากที่นั่นไปได้ +- JavaScript ติดต่อสื่อสารกับเซิร์ฟเวอร์ที่หน้านั้นมาจากได้โดยง่าย แต่ความสามารถในการรับข้อมูลจากโดเมนหรือไซต์อื่นๆ นั้นถูกจำกัด เป็นไปได้แต่ต้องมีข้อตกลงชัดเจนจากเซิร์ฟเวอร์ปลายทาง (แสดงด้วย HTTP header) เป็นข้อจำกัดทางความปลอดภัยอีกเช่นกัน + +![](limitations.svg) + +ข้อจำกัดเหล่านี้ไม่มีการบังคับใช้เลยหาก JavaScript ทำงานนอกเบราว์เซอร์ เช่นบนเซิร์ฟเวอร์ สำหรับเบราว์เซอร์สมัยใหม่ก็อนุญาตให้ปลั๊กอิน/ส่วนขยายขอสิทธิ์เพิ่มเติมได้ +======= There are ways to interact with the camera/microphone and other devices, but they require a user's explicit permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the [NSA](https://en.wikipedia.org/wiki/National_Security_Agency). - Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other page if they come from different sites (from a different domain, protocol or port). @@ -78,34 +105,52 @@ Examples of such restrictions include: ![](limitations.svg) Such limitations do not exist if JavaScript is used outside of the browser, for example on a server. Modern browsers also allow plugins/extensions which may ask for extended permissions. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -## What makes JavaScript unique? +## อะไรที่ทำให้ JavaScript โดดเด่นเป็นเอกลักษณ์? -There are at least *three* great things about JavaScript: +JavaScript มีอย่างน้อย *3 คุณสมบัติ* ที่โดดเด่น: ```compare -+ Full integration with HTML/CSS. -+ Simple things are done simply. -+ Supported by all major browsers and enabled by default. ++ ผสานเข้ากับ HTML/CSS ได้อย่างลงตัว ++ ทำสิ่งง่ายๆ ได้อย่างง่ายดาย ++ รองรับโดยเบราว์เซอร์หลักทั้งหมด และเปิดใช้งานเป็นค่าเริ่มต้น ``` -JavaScript is the only browser technology that combines these three things. -That's what makes JavaScript unique. That's why it's the most widespread tool for creating browser interfaces. +JavaScript เป็นเทคโนโลยีเบราว์เซอร์เพียงอย่างเดียวที่รวมทั้ง 3 คุณสมบัตินี้เข้าด้วยกัน +<<<<<<< HEAD +ด้วยคุณสมบัติเฉพาะตัวเหล่านี้ ทำให้ JavaScript กลายเป็นเครื่องมือที่ได้รับความนิยมอย่างกว้างขวางในการสร้างส่วนติดต่อผู้ใช้บนเบราว์เซอร์ +======= That said, JavaScript can be used to create servers, mobile applications, etc. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -## Languages "over" JavaScript +อย่างไรก็ตาม ปัจจุบัน JavaScript ยังสามารถใช้สร้างเซิร์ฟเวอร์ แอปพลิเคชันมือถือ และอื่นๆ ได้อีกด้วย -The syntax of JavaScript does not suit everyone's needs. Different people want different features. +## ภาษาที่ถูก "transpile" เป็น JavaScript -That's to be expected, because projects and requirements are different for everyone. +ไวยากรณ์ของ JavaScript อาจไม่ตอบโจทย์ความต้องการของทุกคน แต่ละคนต้องการฟีเจอร์ที่แตกต่างกันไป +<<<<<<< HEAD +ซึ่งเป็นเรื่องที่เข้าใจได้ เพราะแต่ละโปรเจกต์และความต้องการของแต่ละคนมีความแตกต่างกัน +======= So, recently a plethora of new languages appeared, which are *transpiled* (converted) to JavaScript before they run in the browser. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +ดังนั้น จึงมีภาษาโปรแกรมใหม่ๆ เกิดขึ้นมากมายในช่วงไม่นานมานี้ โดยภาษาเหล่านี้จะถูก *transpile* (แปลง) เป็น JavaScript ก่อนที่จะทำงานในเบราว์เซอร์ -Modern tools make the transpilation very fast and transparent, actually allowing developers to code in another language and auto-converting it "under the hood". +เครื่องมือสมัยใหม่ทำให้ขั้นตอนการ transpile เป็นไปได้อย่างรวดเร็วและโปร่งใส ทำให้นักพัฒนาสามารถเขียนโค้ดด้วยภาษาอื่น แล้วแปลงเป็น JavaScript โดยอัตโนมัติเบื้องหลังได้ -Examples of such languages: +<<<<<<< HEAD +ตัวอย่างของภาษาเหล่านั้น ได้แก่: +- [CoffeeScript](https://coffeescript.org/) เป็น "syntactic sugar" สำหรับ JavaScript โดยนำเสนอไวยากรณ์ที่กระชับกว่า ช่วยให้เราเขียนโค้ดได้ชัดเจนและถูกต้องมากขึ้น เป็นที่นิยมในหมู่นักพัฒนา Ruby +- [TypeScript](https://www.typescriptlang.org/) เน้นการเพิ่ม "strict data typing" เพื่อให้การพัฒนาและดูแลระบบที่ซับซ้อนง่ายขึ้น พัฒนาโดย Microsoft +- [Flow](https://flow.org/) ก็เพิ่ม data typing เช่นกัน แต่ในรูปแบบที่แตกต่างออกไป พัฒนาโดย Facebook +- [Dart](https://www.dartlang.org/) เป็นภาษาแยกต่างหากที่มี engine เป็นของตัวเอง สามารถทำงานในสภาพแวดล้อมที่ไม่ใช่เบราว์เซอร์ได้ (เช่น แอปมือถือ) และยังสามารถ transpile เป็น JavaScript ได้ พัฒนาโดย Google +- [Brython](https://brython.info/) เป็น transpiler ที่แปลง Python เป็น JavaScript ทำให้สามารถเขียนแอปด้วย Python บริสุทธิ์ได้โดยไม่ต้องใช้ JavaScript +- [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) เป็นภาษาโปรแกรมสมัยใหม่ที่กระชับและปลอดภัย สามารถกำหนดเป้าหมายไปที่เบราว์เซอร์หรือ Node ได้ +======= - [CoffeeScript](https://coffeescript.org/) is "syntactic sugar" for JavaScript. It introduces shorter syntax, allowing us to write clearer and more precise code. Usually, Ruby devs like it. - [TypeScript](https://www.typescriptlang.org/) is concentrated on adding "strict data typing" to simplify the development and support of complex systems. It is developed by Microsoft. - [Flow](https://flow.org/) also adds data typing, but in a different way. Developed by Facebook. @@ -114,9 +159,12 @@ Examples of such languages: - [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) is a modern, concise and safe programming language that can target the browser or Node. There are more. Of course, even if we use one of these transpiled languages, we should also know JavaScript to really understand what we're doing. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +มีภาษาอื่นๆ อีกมากมาย แม้จะใช้ภาษาเหล่านี้ก็จริง แต่การศึกษา JavaScript เองก็ยังมีความจำเป็น เพื่อให้เข้าใจอย่างถ่องแท้ว่ากำลังทำอะไรอยู่ -## Summary +## สรุป -- JavaScript was initially created as a browser-only language, but it is now used in many other environments as well. -- Today, JavaScript has a unique position as the most widely-adopted browser language, fully integrated with HTML/CSS. -- There are many languages that get "transpiled" to JavaScript and provide certain features. It is recommended to take a look at them, at least briefly, after mastering JavaScript. +- JavaScript ถูกสร้างขึ้นมาเพื่อใช้เป็นภาษาสำหรับเบราว์เซอร์โดยเฉพาะ แต่ปัจจุบันก็ถูกนำไปใช้ในสภาพแวดล้อมอื่นๆ มากมาย +- ในปัจจุบัน JavaScript มีบทบาทสำคัญในฐานะภาษาเบราว์เซอร์ที่ได้รับการยอมรับอย่างกว้างขวางที่สุด โดยสามารถทำงานร่วมกับ HTML/CSS ได้อย่างลงตัว +- มีภาษาอีกหลายภาษาที่ถูก "transpile" เป็น JavaScript และมีฟีเจอร์เสริมบางอย่าง แนะนำให้ลองศึกษาคร่าวๆ หลังจากที่เชี่ยวชาญ JavaScript แล้ว diff --git a/1-js/01-getting-started/2-manuals-specifications/article.md b/1-js/01-getting-started/2-manuals-specifications/article.md index 3fa243336..cb114726c 100644 --- a/1-js/01-getting-started/2-manuals-specifications/article.md +++ b/1-js/01-getting-started/2-manuals-specifications/article.md @@ -1,37 +1,58 @@ +# คู่มือและข้อกำหนด -# Manuals and specifications +หนังสือเล่มนี้เป็น *บทเรียน* ที่มุ่งหวังให้คุณค่อยๆ เรียนรู้ภาษา JavaScript อย่างเป็นขั้นเป็นตอน แต่เมื่อคุณคุ้นเคยกับพื้นฐานแล้ว คุณอาจต้องการแหล่งข้อมูลอ้างอิงเพิ่มเติม ดังนี้ +<<<<<<< HEAD +## ข้อกำหนด +======= This book is a *tutorial*. It aims to help you gradually learn the language. But once you're familiar with the basics, you'll need other resources. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -## Specification +[ข้อกำหนด ECMA-262](https://www.ecma-international.org/publications/standards/Ecma-262.htm) เป็นเอกสารที่มีรายละเอียดเชิงลึก ครบถ้วน และเป็นทางการที่สุดเกี่ยวกับ JavaScript เป็นตัวกำหนดมาตรฐานของภาษานี้ -[The ECMA-262 specification](https://www.ecma-international.org/publications/standards/Ecma-262.htm) contains the most in-depth, detailed and formalized information about JavaScript. It defines the language. +แต่เนื่องจากมีลักษณะเป็นทางการมาก จึงอาจทำความเข้าใจได้ยากในช่วงแรก ดังนั้น หากคุณต้องการแหล่งอ้างอิงที่ถูกต้องที่สุดเกี่ยวกับรายละเอียดต่างๆ ของภาษา ข้อกำหนดนี้คือสิ่งที่คุณควรใช้ แต่อาจไม่เหมาะสำหรับการอ้างอิงในชีวิตประจำวัน -But being that formalized, it's difficult to understand at first. So if you need the most trustworthy source of information about the language details, the specification is the right place. But it's not for everyday use. +ข้อกำหนดเวอร์ชันใหม่จะถูกปล่อยออกมาเป็นประจำทุกปี ในระหว่างช่วงที่ยังไม่มีการปล่อยเวอร์ชันใหม่ สามารถดูร่างข้อกำหนดล่าสุดได้ที่ +<<<<<<< HEAD +หากคุณต้องการอ่านเกี่ยวกับคุณสมบัติใหม่ล่าสุด รวมถึงคุณสมบัติที่ "ใกล้จะเป็นมาตรฐาน" (หรือที่เรียกว่า "stage 3") สามารถดูได้ที่ +======= A new specification version is released every year. Between these releases, the latest specification draft is at . +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -To read about new bleeding-edge features, including those that are "almost standard" (so-called "stage 3"), see proposals at . +นอกจากนี้ ถ้าคุณกำลังพัฒนาเว็บสำหรับเบราว์เซอร์ จะมีข้อกำหนดเพิ่มเติมอื่นๆ ที่กล่าวถึงใน[ส่วนที่สอง](info:browser-environment) ของบทเรียนนี้ -Also, if you're developing for the browser, then there are other specifications covered in the [second part](info:browser-environment) of the tutorial. +## คู่มืออ้างอิง -## Manuals +- **MDN (Mozilla) JavaScript Reference** เป็นคู่มือหลักที่มีตัวอย่างและข้อมูลเชิงลึกอื่นๆ เป็นแหล่งข้อมูลที่ยอดเยี่ยมสำหรับการค้นหารายละเอียดเกี่ยวกับฟังก์ชัน เมท็อด และอื่นๆ ในภาษานี้ -- **MDN (Mozilla) JavaScript Reference** is the main manual with examples and other information. It's great to get in-depth information about individual language functions, methods etc. + สามารถเข้าถึงได้ที่ +<<<<<<< HEAD + อย่างไรก็ตาม บ่อยครั้งแล้วการค้นหาโดยใช้ Google จะสะดวกกว่า เพียงพิมพ์ "MDN [คำที่ต้องการค้นหา]" เช่น ค้นหา เพื่อหาข้อมูลเกี่ยวกับฟังก์ชัน `parseInt` + +## ตารางความเข้ากันได้ +======= You can find it at . Although, it's often best to use an internet search instead. Just use "MDN [term]" in the query, e.g. to search for the `parseInt` function. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +JavaScript เป็นภาษาที่มีการพัฒนาอย่างต่อเนื่อง มีการเพิ่มคุณสมบัติใหม่ๆ เป็นประจำ -## Compatibility tables +เพื่อตรวจสอบว่าคุณสมบัติต่างๆ นั้นรองรับโดยเบราว์เซอร์และเอ็นจิ้นอื่นๆ มากน้อยเพียงใด สามารถดูได้จาก: -JavaScript is a developing language, new features get added regularly. +- - แสดงตารางการรองรับคุณสมบัติแยกตามหมวดหมู่ เช่น หากต้องการดูว่าเอ็นจิ้นใดบ้างที่รองรับฟังก์ชันการเข้ารหัสลับสมัยใหม่ สามารถค้นหาได้ที่ -To see their support among browser-based and other engines, see: +<<<<<<< HEAD +- - ตารางแสดงคุณสมบัติต่างๆ ของภาษา และระบุว่าเอ็นจิ้นใดรองรับหรือไม่รองรับบ้าง +แหล่งข้อมูลเหล่านี้มีประโยชน์อย่างมากในการพัฒนาจริง เนื่องจากมีข้อมูลที่สำคัญเกี่ยวกับรายละเอียดของภาษา ความเข้ากันได้ และอื่นๆ +======= - - per-feature tables of support, e.g. to see which engines support modern cryptography functions: . - - a table with language features and engines that support those or don't support. All these resources are useful in real-life development, as they contain valuable information about language details, their support, etc. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Please remember them (or this page) for the cases when you need in-depth information about a particular feature. +โปรดจดจำแหล่งอ้างอิงเหล่านี้ (หรือบุ๊กมาร์กหน้านี้ไว้) เพื่อใช้ในยามที่คุณต้องการข้อมูลเชิงลึกเกี่ยวกับคุณสมบัติเฉพาะใดๆ ของภาษา diff --git a/1-js/01-getting-started/3-code-editors/article.md b/1-js/01-getting-started/3-code-editors/article.md index ca6194741..7b8338e40 100644 --- a/1-js/01-getting-started/3-code-editors/article.md +++ b/1-js/01-getting-started/3-code-editors/article.md @@ -1,49 +1,71 @@ -# Code editors +# ตัวแก้ไขโค้ด -A code editor is the place where programmers spend most of their time. +ตัวแก้ไขโค้ด (code editor) คือเครื่องมือที่โปรแกรมเมอร์ใช้เวลาส่วนใหญ่ในการทำงานด้วย -There are two main types of code editors: IDEs and lightweight editors. Many people use one tool of each type. +ตัวแก้ไขโค้ดมีสองประเภทหลักๆ คือ IDE และตัวแก้ไขแบบเบา (lightweight editor) ซึ่งนักพัฒนาหลายคนมักจะใช้ทั้งสองแบบควบคู่กันไป ## IDE -The term [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) (Integrated Development Environment) refers to a powerful editor with many features that usually operates on a "whole project." As the name suggests, it's not just an editor, but a full-scale "development environment." +[IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) ย่อมาจาก Integrated Development Environment หมายถึงตัวแก้ไขโค้ดที่มีความสามารถสูง พร้อมฟีเจอร์ต่างๆ มากมาย โดยมักจะทำงานในระดับ "โปรเจ็กต์ทั้งหมด" ตามชื่อที่บ่งบอก มันไม่ใช่แค่ตัวแก้ไขธรรมดา แต่เป็น "สภาพแวดล้อมการพัฒนา" อย่างครบวงจร -An IDE loads the project (which can be many files), allows navigation between files, provides autocompletion based on the whole project (not just the open file), and integrates with a version management system (like [git](https://git-scm.com/)), a testing environment, and other "project-level" stuff. +IDE จะโหลดโครงการ (ซึ่งอาจประกอบด้วยหลายไฟล์) เข้ามา ช่วยให้เราสามารถสลับไปมาระหว่างไฟล์ต่างๆ ได้ มีระบบเติมโค้ดอัตโนมัติตามบริบทของโปรเจ็กต์ทั้งหมด (ไม่ใช่เฉพาะไฟล์ที่กำลังเปิดอยู่) และเชื่อมต่อกับระบบจัดการเวอร์ชัน เช่น [git](https://git-scm.com/) รวมถึงมีการผนวกรวมกับสภาพแวดล้อมการทดสอบ และอื่นๆ ในระดับของโครงการด้วย -If you haven't selected an IDE yet, consider the following options: +หากคุณยังไม่เคยเลือกใช้ IDE มาก่อน ลองพิจารณาตัวเลือกเหล่านี้ดู: +<<<<<<< HEAD +- [Visual Studio Code](https://code.visualstudio.com/) (รองรับหลายแพลตฟอร์ม, ฟรี) +- [WebStorm](https://www.jetbrains.com/webstorm/) (รองรับหลายแพลตฟอร์ม, มีค่าใช้จ่าย) +======= - [Visual Studio Code](https://code.visualstudio.com/) (cross-platform, free). - [WebStorm](https://www.jetbrains.com/webstorm/) (cross-platform, paid). +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -For Windows, there's also "Visual Studio", not to be confused with "Visual Studio Code". "Visual Studio" is a paid and mighty Windows-only editor, well-suited for the .NET platform. It's also good at JavaScript. There's also a free version [Visual Studio Community](https://www.visualstudio.com/vs/community/). +สำหรับ Windows ยังมี "Visual Studio" ด้วย อย่าสับสนกับ "Visual Studio Code" นะ "Visual Studio" เป็น IDE ที่ทรงพลังและเสียค่าใช้จ่าย มีเฉพาะบน Windows เท่านั้น เหมาะสำหรับการพัฒนาบนแพลตฟอร์ม .NET และสามารถใช้งานกับ JavaScript ได้เป็นอย่างดีเช่นกัน โดยมีเวอร์ชันฟรีชื่อ [Visual Studio Community](https://www.visualstudio.com/vs/community/) -Many IDEs are paid, but have a trial period. Their cost is usually negligible compared to a qualified developer's salary, so just choose the best one for you. +IDE หลายตัวมีค่าใช้จ่าย แต่ก็มีระยะทดลองใช้ฟรี ซึ่งเมื่อเทียบกับเงินเดือนของนักพัฒนาที่ดีแล้ว ค่าใช้จ่ายเหล่านั้นถือว่าน้อยมาก ดังนั้นควรเลือกตัวที่เหมาะสมกับตัวเองที่สุด -## Lightweight editors +## ตัวแก้ไขแบบเบา -"Lightweight editors" are not as powerful as IDEs, but they're fast, elegant and simple. +ตัวแก้ไขแบบเบา (lightweight editor) อาจจะไม่ทรงพลังเท่า IDE แต่มันมีความเร็ว เบา และเรียบง่าย -They are mainly used to open and edit a file instantly. +ส่วนใหญ่แล้วจะใช้เพื่อเปิดและแก้ไขไฟล์ได้อย่างรวดเร็ว -The main difference between a "lightweight editor" and an "IDE" is that an IDE works on a project-level, so it loads much more data on start, analyzes the project structure if needed and so on. A lightweight editor is much faster if we need only one file. +ความแตกต่างหลักระหว่าง "ตัวแก้ไขแบบเบา" กับ "IDE" ก็คือ IDE จะทำงานในระดับโปรเจ็กต์ ดังนั้นตอนเริ่มต้นโหลดมันจะใช้เวลามากกว่า ต้องวิเคราะห์โครงสร้างโปรเจ็กต์หากจำเป็น และอื่นๆ อีกมาก ส่วนตัวแก้ไขแบบเบานั้นจะเปิดไฟล์ได้เร็วกว่ามาก -In practice, lightweight editors may have a lot of plugins including directory-level syntax analyzers and autocompleters, so there's no strict border between a lightweight editor and an IDE. +ในทางปฏิบัติ ตัวแก้ไขแบบเบาก็อาจมีปลั๊กอินต่างๆ เพิ่มเข้ามาได้มากมาย รวมถึงมีตัวช่วยวิเคราะห์ไวยากรณ์และระบบเติมโค้ดอัตโนมัติในระดับไดเรกทอรี ทำให้แยกความแตกต่างระหว่างตัวแก้ไขแบบเบากับ IDE ได้ไม่ชัดเจนนัก +<<<<<<< HEAD +มีตัวเลือกมากมาย เช่น: + +- [Sublime Text](https://www.sublimetext.com/) (รองรับหลายแพลตฟอร์ม, shareware) +- [Notepad++](https://notepad-plus-plus.org/) (Windows, ฟรี) +- [Vim](https://www.vim.org/) และ [Emacs](https://www.gnu.org/software/emacs/) ก็เจ๋งมากหากคุณรู้วิธีใช้ +======= There are many options, for instance: - [Sublime Text](https://www.sublimetext.com/) (cross-platform, shareware). - [Notepad++](https://notepad-plus-plus.org/) (Windows, free). - [Vim](https://www.vim.org/) and [Emacs](https://www.gnu.org/software/emacs/) are also cool if you know how to use them. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +## อย่าถกเถียงกันเลย + +ตัวแก้ไขโค้ดที่ยกตัวอย่างมาข้างต้น เป็นที่นิยมใช้กันมานานแล้วในหมู่ผู้เขียนและเพื่อนๆ ที่เป็นนักพัฒนาชั้นยอด และทุกคนก็พอใจกับมัน -## Let's not argue +แน่นอนว่ายังมีตัวแก้ไขโค้ดอื่นๆ อีกมากมายในโลกกว้าง เลือกใช้ตัวที่คุณชื่นชอบที่สุดแล้วกัน -The editors in the lists above are those that either I or my friends whom I consider good developers have been using for a long time and are happy with. +<<<<<<< HEAD +การเลือกใช้ตัวแก้ไขโค้ด ก็เหมือนกับการเลือกใช้เครื่องมืออื่นๆ เป็นเรื่องของรสนิยมส่วนบุคคล และขึ้นอยู่กับประเภทของโปรเจ็กต์ นิสัยการทำงาน และความชอบเฉพาะตัวของแต่ละคน -There are other great editors in our big world. Please choose the one you like the most. +ความเห็นส่วนตัวของผู้เขียน: +- ผมใช้ [Visual Studio Code](https://code.visualstudio.com/) หากพัฒนา frontend (ฝั่งหน้าบ้าน) เป็นหลัก +- แต่หากใช้ภาษา/แพลตฟอร์มอื่นๆ เป็นส่วนใหญ่ โดยมี frontend แค่บางส่วน ผมจะพิจารณาใช้ตัวอื่น เช่น XCode (Mac), Visual Studio (Windows) หรือ IDE จากค่าย Jetbrains (WebStorm สำหรับ JavaScript, PHPStorm สำหรับ PHP, RubyMine สำหรับ Ruby เป็นต้น) ทั้งนี้ขึ้นอยู่กับภาษาหลักของโปรเจ็กต์ +======= The choice of an editor, like any other tool, is individual and depends on your projects, habits, and personal preferences. The author's personal opinion: - I'd use [Visual Studio Code](https://code.visualstudio.com/) if I develop mostly frontend. - Otherwise, if it's mostly another language/platform and partially frontend, then consider other editors, such as XCode (Mac), Visual Studio (Windows) or Jetbrains family (Webstorm, PHPStorm, RubyMine etc, depending on the language). +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 diff --git a/1-js/01-getting-started/4-devtools/article.md b/1-js/01-getting-started/4-devtools/article.md index bbe8af920..5551a8b23 100644 --- a/1-js/01-getting-started/4-devtools/article.md +++ b/1-js/01-getting-started/4-devtools/article.md @@ -1,63 +1,67 @@ -# Developer console +# คอนโซลนักพัฒนา -Code is prone to errors. You will quite likely make errors... Oh, what am I talking about? You are *absolutely* going to make errors, at least if you're a human, not a [robot](https://en.wikipedia.org/wiki/Bender_(Futurama)). +เมื่อเขียนโค้ด มักจะเกิดข้อผิดพลาดได้เสมอ ไม่ว่าคุณจะระมัดระวังแค่ไหน ก็ยังมีโอกาสทำผิดพลาดอยู่ดี... เอ่อ กำลังพูดถึงอะไรอยู่น่ะ? ต้องขอแก้ใหม่ หากคุณเป็นมนุษย์ คุณ *จะต้อง* ทำผิดพลาดแน่ๆ ยกเว้นว่าคุณจะเป็น[หุ่นยนต์](https://en.wikipedia.org/wiki/Bender_(Futurama)) -But in the browser, users don't see errors by default. So, if something goes wrong in the script, we won't see what's broken and can't fix it. +แต่โดยค่าเริ่มต้น ผู้ใช้จะไม่เห็นข้อผิดพลาดเหล่านั้นบนหน้าเว็บ ดังนั้น หากสคริปต์มีจุดบกพร่อง เราจะไม่รู้ว่ามันพังตรงไหน ทำให้ไม่สามารถแก้ไขได้ -To see errors and get a lot of other useful information about scripts, "developer tools" have been embedded in browsers. +เพื่อให้เห็นข้อผิดพลาดและข้อมูลดีบั๊กที่มีประโยชน์อื่นๆ เกี่ยวกับสคริปต์ เบราว์เซอร์จึงมี "เครื่องมือนักพัฒนา" (developer tools) ติดตั้งมาด้วย -Most developers lean towards Chrome or Firefox for development because those browsers have the best developer tools. Other browsers also provide developer tools, sometimes with special features, but are usually playing "catch-up" to Chrome or Firefox. So most developers have a "favorite" browser and switch to others if a problem is browser-specific. +นักพัฒนาส่วนใหญ่นิยมใช้ Chrome หรือ Firefox ในการพัฒนา เพราะมีเครื่องมือนักพัฒนาที่ทรงพลังที่สุด แม้ว่าเบราว์เซอร์อื่นๆ ก็มีเครื่องมือที่คล้ายกัน บางทีอาจจะมีฟีเจอร์พิเศษด้วย แต่มักจะตามหลัง Chrome หรือ Firefox เสมอ ดังนั้นนักพัฒนาจึงมักมีเบราว์เซอร์ "โปรด" สำหรับทำงาน และเปลี่ยนไปใช้เบราว์เซอร์อื่นเป็นครั้งคราวเมื่อพบปัญหาเฉพาะของเบราว์เซอร์นั้น -Developer tools are potent; they have many features. To start, we'll learn how to open them, look at errors, and run JavaScript commands. +เครื่องมือนักพัฒนานั้นมีประสิทธิภาพสูงและมีฟีเจอร์มากมาย ในช่วงแรก เราจะเรียนรู้วิธีเปิดใช้งาน ดูข้อผิดพลาด และรันคำสั่ง JavaScript กัน ## Google Chrome -Open the page [bug.html](bug.html). +ลองเปิดหน้า [bug.html](bug.html) ดู -There's an error in the JavaScript code on it. It's hidden from a regular visitor's eyes, so let's open developer tools to see it. +ในโค้ด JavaScript บนหน้านั้นมีบั๊กซ่อนอยู่ มันถูกซ่อนไว้จากสายตาผู้ใช้ทั่วไป เราลองเปิดเครื่องมือนักพัฒนาเพื่อมองหามันกัน -Press `key:F12` or, if you're on Mac, then `key:Cmd+Opt+J`. +กด `key:F12` หรือหากใช้ Mac ให้กด `key:Cmd+Opt+J` -The developer tools will open on the Console tab by default. +เครื่องมือนักพัฒนาจะเปิดขึ้นที่แท็บ Console เป็นค่าเริ่มต้น -It looks somewhat like this: +หน้าตาจะออกมาประมาณนี้: ![chrome](chrome.webp) -The exact look of developer tools depends on your version of Chrome. It changes from time to time but should be similar. +รูปลักษณ์ที่แน่นอนของเครื่องมือนักพัฒนาขึ้นอยู่กับเวอร์ชันของ Chrome ที่ใช้ มันมีการเปลี่ยนแปลงไปเรื่อยๆ แต่น่าจะคล้ายๆ กับในภาพ -- Here we can see the red-colored error message. In this case, the script contains an unknown "lalala" command. -- On the right, there is a clickable link to the source `bug.html:12` with the line number where the error has occurred. +- ตรงนี้เราจะเห็นข้อความแสดงข้อผิดพลาดสีแดง ในกรณีนี้ สคริปต์มีคำสั่งที่ไม่รู้จักชื่อ "lalala" +- ทางด้านขวา จะมีลิงก์ที่คลิกได้ ซึ่งจะระบุไฟล์ต้นทาง `bug.html:12` พร้อมเลขบรรทัดที่เกิดข้อผิดพลาด -Below the error message, there is a blue `>` symbol. It marks a "command line" where we can type JavaScript commands. Press `key:Enter` to run them. +ใต้ข้อความแสดงข้อผิดพลาดจะมีสัญลักษณ์ `>` สีฟ้า นี่คือ "บรรทัดคำสั่ง" (command line) ที่เราสามารถพิมพ์คำสั่ง JavaScript แล้วกด `key:Enter` เพื่อรันมันได้ -Now we can see errors, and that's enough for a start. We'll come back to developer tools later and cover debugging more in-depth in the chapter . +ตอนนี้เราก็เห็นข้อผิดพลาดแล้ว ซึ่งเพียงพอสำหรับการเริ่มต้น เราจะกลับมาศึกษาเครื่องมือนักพัฒนากันอีกในภายหลัง และจะคุยเรื่องการดีบั๊กอย่างละเอียดมากขึ้นในบท -```smart header="Multi-line input" -Usually, when we put a line of code into the console, and then press `key:Enter`, it executes. +```smart header="การป้อนหลายบรรทัด" +โดยปกติ เมื่อเราพิมพ์โค้ดบรรทัดเดียวลงไปในคอนโซล และกด `key:Enter` มันจะรันคำสั่งนั้นทันที -To insert multiple lines, press `key:Shift+Enter`. This way one can enter long fragments of JavaScript code. +แต่ถ้าต้องการพิมพ์หลายบรรทัด ให้กด `key:Shift+Enter` แทน วิธีนี้จะช่วยให้เราใส่ชิ้นส่วนโค้ด JavaScript ยาวๆ ได้ ``` -## Firefox, Edge, and others +## Firefox, Edge และอื่นๆ -Most other browsers use `key:F12` to open developer tools. +เบราว์เซอร์ส่วนใหญ่ใช้ `key:F12` เพื่อเปิดเครื่องมือนักพัฒนา -The look & feel of them is quite similar. Once you know how to use one of these tools (you can start with Chrome), you can easily switch to another. +ลักษณะและความรู้สึกในการใช้งานค่อนข้างใกล้เคียงกัน เมื่อคุณรู้วิธีใช้เครื่องมือใดเครื่องมือหนึ่ง (เช่น เริ่มจาก Chrome) คุณก็สามารถเปลี่ยนไปใช้อันอื่นๆ ได้อย่างง่ายดาย ## Safari -Safari (Mac browser, not supported by Windows/Linux) is a little bit special here. We need to enable the "Develop menu" first. +Safari (เบราว์เซอร์ของ Mac ไม่รองรับ Windows/Linux) จะแตกต่างออกไปเล็กน้อย เราต้องเปิดใช้งาน "Develop menu" ก่อน +<<<<<<< HEAD +ไปที่ Preferences และเลือกแท็บ "Advanced" จะเห็นช่องทำเครื่องหมายที่ด้านล่างของหน้า: +======= Open Settings and go to the "Advanced" pane. There's a checkbox at the bottom: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ![safari](safari.png) -Now `key:Cmd+Opt+C` can toggle the console. Also, note that the new top menu item named "Develop" has appeared. It has many commands and options. +ตอนนี้ `key:Cmd+Opt+C` จะสามารถเปิด/ปิดคอนโซลได้ และสังเกตว่าจะมีเมนูใหม่ชื่อ "Develop" ปรากฏที่ด้านบนขวา ซึ่งมีคำสั่งและตัวเลือกต่างๆ มากมาย -## Summary +## สรุป -- Developer tools allow us to see errors, run commands, examine variables, and much more. -- They can be opened with `key:F12` for most browsers on Windows. Chrome for Mac needs `key:Cmd+Opt+J`, Safari: `key:Cmd+Opt+C` (need to enable first). +- เครื่องมือนักพัฒนาช่วยให้เราเห็นข้อผิดพลาด รันคำสั่ง ตรวจสอบตัวแปร และอีกสารพัด +- สามารถเปิดใช้งานได้ด้วย `key:F12` ในเบราว์เซอร์ส่วนใหญ่บน Windows ส่วน Chrome บน Mac ใช้ `key:Cmd+Opt+J`, Safari ใช้ `key:Cmd+Opt+C` (ต้องเปิดใช้ก่อน) -Now we have the environment ready. In the next section, we'll get down to JavaScript. +ตอนนี้เตรียมสภาพแวดล้อมเรียบร้อยแล้ว ในบทต่อๆ ไป เราจะเริ่มศึกษา JavaScript อย่างละเอียดมากขึ้น diff --git a/1-js/01-getting-started/index.md b/1-js/01-getting-started/index.md index b327c7860..685f6dad9 100644 --- a/1-js/01-getting-started/index.md +++ b/1-js/01-getting-started/index.md @@ -1,3 +1,3 @@ -# An introduction +# บทนำ -About the JavaScript language and the environment to develop with it. +ในบทนี้เราจะพูดถึงเกี่ยวกับภาษา JavaScript และสภาพแวดล้อมที่ใช้ในการพัฒนาโปรแกรมด้วยภาษานี้ diff --git a/1-js/02-first-steps/01-hello-world/1-hello-alert/task.md b/1-js/02-first-steps/01-hello-world/1-hello-alert/task.md index afed6a91d..b1f35ea9b 100644 --- a/1-js/02-first-steps/01-hello-world/1-hello-alert/task.md +++ b/1-js/02-first-steps/01-hello-world/1-hello-alert/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Show an alert +# โชว์หน้าแจ้งเตือน -Create a page that shows a message "I'm JavaScript!". +สร้างเว็บเพจที่เปิดขึ้นมาจะแสดงหน้าต่าง `alert` ว่า "I'm JavaScript!". -Do it in a sandbox, or on your hard drive, doesn't matter, just ensure that it works. +ที่นี่เป็นพื้นที่การเล่นที่ปลอดภัย ดังนั้นไม่ต้องกังวลว่าคอมพิวเตอร์จะเสียหาย [demo src="solution"] diff --git a/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/solution.md b/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/solution.md index f42c41e6d..0fa1300cf 100644 --- a/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/solution.md +++ b/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/solution.md @@ -1,8 +1,8 @@ -The HTML code: +HTML: [html src="index.html"] -For the file `alert.js` in the same folder: +สำหรับไฟล์ `alert.js` อยู่ในโฟลเดอร์เดียวกัน: [js src="alert.js"] diff --git a/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md b/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md index 26168d6a7..f5d000b28 100644 --- a/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md +++ b/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md @@ -2,8 +2,8 @@ importance: 5 --- -# Show an alert with an external script +# โชว์หน้าแจ้งเตือนด้วยสคริปต์จากภายนอก -Take the solution of the previous task . Modify it by extracting the script content into an external file `alert.js`, residing in the same folder. +ใช้ความรู้จากแบบฝึกหัดที่แล้ว ช่วยบอกเบราเซอร์ให้รู้ว่าที่อยู่ของไฟล์ `alert.js` อยู่ที่ใด ขอใบ้ว่าอยู่ในโฟลเดอร์เดียวกัน -Open the page, ensure that the alert works. +เปิดหน้าเว็บขึ้นมา เพื่อดูว่าสคริปต์ทำงานได้ตามที่คาดหวังไว้ diff --git a/1-js/02-first-steps/01-hello-world/article.md b/1-js/02-first-steps/01-hello-world/article.md index 35f82bf5d..b7a200589 100644 --- a/1-js/02-first-steps/01-hello-world/article.md +++ b/1-js/02-first-steps/01-hello-world/article.md @@ -1,17 +1,16 @@ -# Hello, world! +# สวัสดี ชาวโลก! -This part of the tutorial is about core JavaScript, the language itself. +ในส่วนนี้ของบทเรียน เราจะเริ่มศึกษาเกี่ยวกับพื้นฐานของภาษา JavaScript -But we need a working environment to run our scripts and, since this book is online, the browser is a good choice. We'll keep the amount of browser-specific commands (like `alert`) to a minimum so that you don't spend time on them if you plan to concentrate on another environment (like Node.js). We'll focus on JavaScript in the browser in the [next part](/ui) of the tutorial. +แต่ก่อนอื่น เราต้องมีสภาพแวดล้อมที่พร้อมสำหรับการรันสคริปต์ และเนื่องจากหนังสือเล่มนี้อยู่บนออนไลน์ เบราว์เซอร์จึงเป็นตัวเลือกที่เหมาะสม เราจะพยายามจำกัดการใช้คำสั่งเฉพาะของเบราว์เซอร์ (เช่น `alert`) ให้น้อยที่สุด เพื่อที่คุณจะได้ไม่ต้องเสียเวลากับมันมากนัก หากคุณตั้งใจจะมุ่งเน้นการใช้ JavaScript ในสภาพแวดล้อมอื่นๆ เช่น Node.js ส่วนการใช้ JavaScript ในเบราว์เซอร์โดยเฉพาะจะมีกล่าวถึงในรายละเอียดใน[ส่วนถัดไป](/ui)ของบทเรียน -So first, let's see how we attach a script to a webpage. For server-side environments (like Node.js), you can execute the script with a command like `"node my.js"`. +ดังนั้น ก่อนอื่นเรามาดูกันว่าจะแทรกสคริปต์ลงในหน้าเว็บได้อย่างไร ซึ่งหากเป็นสภาพแวดล้อมฝั่งเซิร์ฟเวอร์อย่าง Node.js เราสามารถรันสคริปต์โดยใช้คำสั่ง `"node my.js"` ได้เลย +## แท็ก "script" -## The "script" tag +โปรแกรม JavaScript สามารถแทรกลงในเอกสาร HTML ได้เกือบทุกที่ด้วยการใช้แท็ก ` */!* -

...After the script.

+

...หลังสคริปต์

@@ -35,24 +34,23 @@ For instance: ``` ```online -You can run the example by clicking the "Play" button in the right-top corner of the box above. +คุณสามารถลองรันตัวอย่างนี้ได้โดยคลิกที่ปุ่ม "เล่น" ที่มุมบนขวาของกล่องโค้ด ``` -The ` ``` - This trick isn't used in modern JavaScript. These comments hide JavaScript code from old browsers that didn't know how to process the ` ``` -Here, `/path/to/script.js` is an absolute path to the script from the site root. One can also provide a relative path from the current page. For instance, `src="script.js"`, just like `src="./script.js"`, would mean a file `"script.js"` in the current folder. +ที่นี่ `/path/to/script.js` คือพาธเต็มไปยังไฟล์สคริปต์นับจากรากของเว็บไซต์ นอกจากนี้คุณยังสามารถระบุพาธสัมพัทธ์จากหน้าปัจจุบันก็ได้ เช่น `src="script.js"` หมายถึงไฟล์ `"script.js"` อยู่ในโฟลเดอร์เดียวกับหน้า HTML ส่วน `src="./script.js"` ก็จะหมายถึงไฟล์ `"script.js"` อยู่ในโฟลเดอร์ปัจจุบันเช่นกัน -We can give a full URL as well. For instance: +เราสามารถระบุ URL แบบเต็มๆ ได้ด้วย เช่น: ```html ``` -To attach several scripts, use multiple tags: +ในการแทรกสคริปต์หลายไฟล์ ให้ใช้แท็กหลายอัน: ```html @@ -90,29 +87,29 @@ To attach several scripts, use multiple tags: ``` ```smart -As a rule, only the simplest scripts are put into HTML. More complex ones reside in separate files. +โดยทั่วไป ในโค้ด HTML จะมีแต่สคริปต์ที่ไม่ซับซ้อนและสั้นๆ เท่านั้น ส่วนโค้ดที่ยาวและซับซ้อนกว่ามักจะแยกไปอยู่ในไฟล์อื่น -The benefit of a separate file is that the browser will download it and store it in its [cache](https://en.wikipedia.org/wiki/Web_cache). +ข้อดีของการแยกสคริปต์ไปอยู่ในไฟล์ต่างหากคือ เบราว์เซอร์จะดาวน์โหลดไฟล์นั้นมาแล้วเก็บไว้ใน[แคช](https://en.wikipedia.org/wiki/Web_cache) -Other pages that reference the same script will take it from the cache instead of downloading it, so the file is actually downloaded only once. +เมื่อหน้าอื่นๆ อ้างถึงสคริปต์ไฟล์เดียวกัน แทนที่จะดาวน์โหลดใหม่ มันจะเรียกใช้ไฟล์จากแคชแทน ทำให้ไฟล์นั้นถูกดาวน์โหลดจริงๆ เพียงแค่ครั้งเดียว -That reduces traffic and makes pages faster. +สิ่งนี้ช่วยลดปริมาณการรับส่งข้อมูลผ่านเครือข่าย ทำให้หน้าเว็บโหลดได้เร็วขึ้น ``` -````warn header="If `src` is set, the script content is ignored." -A single ` ``` -We must choose either an external ` @@ -122,11 +119,10 @@ The example above can be split into two scripts to work: ``` ```` -## Summary - -- We can use a ``. +## สรุป +- เราสามารถใช้แท็ก `` -There is much more to learn about browser scripts and their interaction with the webpage. But let's keep in mind that this part of the tutorial is devoted to the JavaScript language, so we shouldn't distract ourselves with browser-specific implementations of it. We'll be using the browser as a way to run JavaScript, which is very convenient for online reading, but only one of many. +เรายังมีอะไรต้องเรียนรู้อีกมากเกี่ยวกับการใช้สคริปต์ในเบราว์เซอร์และการสื่อสารระหว่างสคริปต์กับหน้าเว็บ แต่อย่าลืมว่าส่วนนี้ของบทเรียนเราจะมุ่งเน้นที่ภาษา JavaScript เอง ดังนั้นเราควรพยายามไม่ออกนอกเรื่องมากเกินไป diff --git a/1-js/02-first-steps/02-structure/article.md b/1-js/02-first-steps/02-structure/article.md index e81fd343d..01cf889d1 100644 --- a/1-js/02-first-steps/02-structure/article.md +++ b/1-js/02-first-steps/02-structure/article.md @@ -1,59 +1,59 @@ -# Code structure +# โครงสร้างโค้ด -The first thing we'll study is the building blocks of code. +ในการเรียนรู้ภาษาโปรแกรมมิ่ง สิ่งแรกที่เราต้องทำความเข้าใจคือบล็อกพื้นฐานของโค้ด ซึ่งได้แก่ statements (คำสั่ง) และ comments (คอมเมนต์) -## Statements +## Statements (คำสั่ง) -Statements are syntax constructs and commands that perform actions. +Statements คือโครงสร้างและคำสั่งทางไวยากรณ์ที่ใช้สั่งให้โปรแกรมทำการกระทำบางอย่าง -We've already seen a statement, `alert('Hello, world!')`, which shows the message "Hello, world!". +เราเคยเห็นตัวอย่างของ statement มาแล้วนั่นคือ `alert('Hello, world!')` ซึ่งเป็นคำสั่งให้แสดงข้อความ "Hello, world!" -We can have as many statements in our code as we want. Statements can be separated with a semicolon. +เราสามารถเขียน statements ในโค้ดได้หลายคำสั่ง โดยแยกแต่ละคำสั่งด้วยเครื่องหมายอัฒภาค (semicolon) -For example, here we split "Hello World" into two alerts: +ตัวอย่างเช่น ที่นี่เราแยก "Hello World" ออกเป็นสอง alerts: ```js run no-beautify alert('Hello'); alert('World'); ``` -Usually, statements are written on separate lines to make the code more readable: +โดยปกติแล้ว statements จะเขียนแยกบรรทัดกันเพื่อให้อ่านโค้ดง่ายขึ้น: ```js run no-beautify alert('Hello'); alert('World'); ``` -## Semicolons [#semicolon] +## เครื่องหมายอัฒภาค (Semicolons) [#semicolon] -A semicolon may be omitted in most cases when a line break exists. +ในหลายกรณี JavaScript อนุญาตให้ละเครื่องหมายอัฒภาคได้ถ้ามีการขึ้นบรรทัดใหม่ -This would also work: +ตัวอย่างเช่น โค้ดนี้จะทำงานได้เหมือนกัน: ```js run no-beautify alert('Hello') -alert('World') +alert('World') ``` -Here, JavaScript interprets the line break as an "implicit" semicolon. This is called an [automatic semicolon insertion](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion). +ที่นี่ JavaScript จะถือว่าการขึ้นบรรทัดใหม่เป็นการใส่เครื่องหมายอัฒภาคโดยนัย เรียกว่า [Automatic Semicolon Insertion](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion) -**In most cases, a newline implies a semicolon. But "in most cases" does not mean "always"!** +**ในหลายๆ กรณี การขึ้นบรรทัดใหม่หมายถึงการใส่เครื่องหมายอัฒภาค แต่ "หลายๆ กรณี" ไม่ได้แปลว่า "เสมอไป"!** -There are cases when a newline does not mean a semicolon. For example: +มีบางสถานการณ์ที่การขึ้นบรรทัดใหม่ไม่ได้หมายถึงการใส่เครื่องหมายอัฒภาค เช่นในตัวอย่างนี้: ```js run no-beautify alert(3 + -1 +1 + 2); ``` -The code outputs `6` because JavaScript does not insert semicolons here. It is intuitively obvious that if the line ends with a plus `"+"`, then it is an "incomplete expression", so a semicolon there would be incorrect. And in this case, that works as intended. +โค้ดจะแสดงผลเป็น `6` เพราะ JavaScript ไม่ได้ใส่เครื่องหมายอัฒภาค มันเข้าใจได้เองว่าถ้าบรรทัดจบด้วย `+` แสดงว่า expression ยังไม่จบ การใส่เครื่องหมายอัฒภาคตรงนั้นจะไม่ถูกต้อง และในกรณีนี้มันก็ทำงานตรงตามที่เราต้องการจริงๆ -**But there are situations where JavaScript "fails" to assume a semicolon where it is really needed.** +**แต่มีบางสถานการณ์ที่ JavaScript "ไม่สามารถ" ใส่เครื่องหมายอัฒภาคให้เราในตำแหน่งที่ควรจะมี** -Errors which occur in such cases are quite hard to find and fix. +ข้อผิดพลาดที่เกิดจากการไม่ใส่เครื่องหมายอัฒภาคมักจะหาสาเหตุและแก้ไขได้ยาก -````smart header="An example of an error" -If you're curious to see a concrete example of such an error, check this code out: +````smart header="ตัวอย่างข้อผิดพลาด" +ถ้าอยากเห็นตัวอย่างของข้อผิดพลาดเช่นนี้ ลองพิจารณาโค้ดนี้ดู: ```js run alert("Hello"); @@ -61,9 +61,9 @@ alert("Hello"); [1, 2].forEach(alert); ``` -No need to think about the meaning of the brackets `[]` and `forEach` yet. We'll study them later. For now, just remember the result of running the code: it shows `Hello`, then `1`, then `2`. +ตอนนี้ไม่ต้องสนใจความหมายของ `[]` และ `forEach` เรายังไม่ได้เรียนเรื่องพวกนี้ เพียงแค่จำไว้ว่ามันจะแสดง `Hello` ตามด้วย `1` และ `2` ในบรรทัดถัดๆ ไป -Now let's remove the semicolon after the `alert`: +ทีนี้ลองลบเครื่องหมายอัฒภาคหลัง `alert` ออกดู: ```js run no-beautify alert("Hello") @@ -71,85 +71,87 @@ alert("Hello") [1, 2].forEach(alert); ``` -The difference compared to the code above is only one character: the semicolon at the end of the first line is gone. +ความต่างจากโค้ดก่อนหน้าคือไม่มีเพียงหนึ่งตัวอักษร นั่นคือเครื่องหมายอัฒภาค `;` ตอนจบบรรทัดแรก -If we run this code, only the first `Hello` shows (and there's an error, you may need to open the console to see it). There are no numbers any more. +ถ้าเรารันโค้ดนี้ มันจะแสดง `Hello` แล้วเกิด error (คุณอาจต้องเปิดคอนโซลเพื่อดูมัน) โดยไม่มีการแสดงเลข 1 และ 2 -That's because JavaScript does not assume a semicolon before square brackets `[...]`. So, the code in the last example is treated as a single statement. +นั่นเป็นเพราะ JavaScript ไม่ได้ใส่เครื่องหมายอัฒภาคโดยอัตโนมัติก่อนวงเล็บ `[...]` ดังนั้น โค้ดในตัวอย่างหลังจึงถูกรวมเป็นคำสั่งเดียวกันหมด -Here's how the engine sees it: +จริงๆ แล้ว JavaScript engine มองเห็นโค้ดเป็นแบบนี้: ```js run no-beautify alert("Hello")[1, 2].forEach(alert); ``` -Looks weird, right? Such merging in this case is just wrong. We need to put a semicolon after `alert` for the code to work correctly. +ดูแปลกๆ ใช่ไหม? การรวมแบบนี้ไม่ถูกต้องแน่นอน เราต้องใส่เครื่องหมายอัฒภาคหลัง `alert` เพื่อให้โค้ดทำงานได้ถูกต้อง -This can happen in other situations also. +ปัญหาแบบนี้อาจเกิดขึ้นได้ในสถานการณ์อื่นๆ ด้วย ```` -We recommend putting semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community. Let's note once again -- *it is possible* to leave out semicolons most of the time. But it's safer -- especially for a beginner -- to use them. +เราแนะนำให้ใส่เครื่องหมายอัฒภาคระหว่าง statements แม้จะแยกคำสั่งด้วยการขึ้นบรรทัดใหม่แล้วก็ตาม กฎนี้เป็นที่ยอมรับอย่างกว้างขวางในชุมชนนักพัฒนา และอีกครั้ง *เราสามารถ* ละเครื่องหมายอัฒภาคได้ในหลายๆ กรณี แต่จะปลอดภัยกว่าโดยเฉพาะสำหรับมือใหม่ถ้าใส่มันไว้ตลอด -## Comments [#code-comments] +## Comments (คอมเมนต์) -As time goes on, programs become more and more complex. It becomes necessary to add *comments* which describe what the code does and why. +เมื่อเวลาผ่านไป โปรแกรมที่เราพัฒนาจะมีความซับซ้อนมากขึ้นเรื่อยๆ จึงจำเป็นต้องมีการเขียน *คอมเมนต์* ที่อธิบายว่าทำไมโค้ดถึงทำแบบนี้และมันทำอะไร -Comments can be put into any place of a script. They don't affect its execution because the engine simply ignores them. +คอมเมนต์สามารถเขียนลงไปได้ทุกที่ในสคริปต์ มันจะไม่ส่งผลต่อการทำงานของโค้ดเพราะ JavaScript engine จะข้ามไปไม่สนใจพวกมัน -**One-line comments start with two forward slash characters `//`.** +**คอมเมนต์บรรทัดเดียวเริ่มต้นด้วย `//`** -The rest of the line is a comment. It may occupy a full line of its own or follow a statement. +เนื้อหาที่เหลือของบรรทัดหลังเครื่องหมาย `//` จะเป็นคอมเมนต์ทั้งหมด มันอาจเป็นคอมเมนต์บรรทัดเดียวเต็มหรือต่อท้ายจาก statement ก็ได้ + +แบบนี้: -Like here: ```js run -// This comment occupies a line of its own +// คอมเมนต์นี้เป็นบรรทัดเดียว alert('Hello'); -alert('World'); // This comment follows the statement +alert('World'); // คอมเมนต์นี้ต่อท้าย statement ``` -**Multiline comments start with a forward slash and an asterisk /* and end with an asterisk and a forward slash */.** +**คอมเมนต์หลายบรรทัดเริ่มด้วย /* และจบด้วย */** -Like this: +แบบนี้: ```js run -/* An example with two messages. -This is a multiline comment. +/* ตัวอย่างที่มีสองข้อความ +นี่คือคอมเมนต์ +หลายบรรทัด */ alert('Hello'); -alert('World'); +alert('World'); ``` -The content of comments is ignored, so if we put code inside /* ... */, it won't execute. +เนื้อหาของคอมเมนต์จะถูกข้ามไปไม่ถูกประมวลผล ดังนั้นถ้าเราใส่โค้ดลงไปใน /* ... */ มันจะไม่ทำงาน -Sometimes it can be handy to temporarily disable a part of code: +บางครั้งมีประโยชน์ในการปิดโค้ดบางส่วนชั่วคราวด้วย: ```js run -/* Commenting out the code +/* ใส่คอมเมนต์โค้ดนี้ alert('Hello'); */ alert('World'); ``` -```smart header="Use hotkeys!" -In most editors, a line of code can be commented out by pressing the `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a piece of code and press the hotkey). For Mac, try `key:Cmd` instead of `key:Ctrl` and `key:Option` instead of `key:Shift`. +```smart header="ใช้ปุ่มลัดเพื่อใส่คอมเมนต์!" +ในเครื่องมือแก้ไขโค้ดส่วนใหญ่ คุณสามารถใส่คอมเมนต์บรรทัดเดียวให้โค้ดได้โดยกด `key:Ctrl+/` สำหรับคอมเมนต์หลายบรรทัด ให้เลือกโค้ดแล้วกด `key:Ctrl+Shift+/` (บน Mac ใช้ `key:Cmd` แทน `key:Ctrl` และ `key:Option` แทน `key:Shift`) ``` -````warn header="Nested comments are not supported!" -There may not be `/*...*/` inside another `/*...*/`. +````warn header="คอมเมนต์ซ้อนกันไม่รองรับ!" +ไม่ควรมี /* ... */ อยู่ข้างในคอมเมนต์หลายบรรทัด /* ... */ อีก -Such code will die with an error: +โค้ดแบบนี้จะเกิดข้อผิดพลาด: ```js run no-beautify /* - /* nested comment ?!? */ + /* คอมเมนต์ซ้อนกัน ?!? */ */ alert( 'World' ); ``` ```` -Please, don't hesitate to comment your code. +อย่าลังเลใจที่จะใส่คอมเมนต์ในโค้ดของคุณ -Comments increase the overall code footprint, but that's not a problem at all. There are many tools which minify code before publishing to a production server. They remove comments, so they don't appear in the working scripts. Therefore, comments do not have negative effects on production at all. +คอมเมนต์อาจจะเพิ่มปริมาณโค้ดให้มากขึ้นแต่นั่นไม่ใช่ปัญหา มีเครื่องมือหลายตัวที่ช่วยลดขนาดสคริปต์ก่อนนำไปเผยแพร่บนเซิร์ฟเวอร์จริง โดยจะตัดคอมเมนต์ทิ้งไปเลยทำให้ไม่ปรากฏในสคริปต์ที่ใช้งานจริง ดังนั้นคอมเมนต์จึงไม่ส่งผลกระทบด้านลบใดๆ ต่อการใช้งาน -Later in the tutorial there will be a chapter that also explains how to write better comments. +ในบทต่อๆ ไปของบทเรียนอย่าง เราจะอธิบายเพิ่มเติมถึงวิธีเขียนคอมเมนต์ที่ดีด้วย diff --git a/1-js/02-first-steps/03-strict-mode/article.md b/1-js/02-first-steps/03-strict-mode/article.md index 9586733cc..24f7ed07f 100644 --- a/1-js/02-first-steps/03-strict-mode/article.md +++ b/1-js/02-first-steps/03-strict-mode/article.md @@ -1,68 +1,68 @@ -# The modern mode, "use strict" +# โหมดสมัยใหม่ "use strict" -For a long time, JavaScript evolved without compatibility issues. New features were added to the language while old functionality didn't change. +เป็นเวลายาวนานที่ JavaScript ถูกพัฒนาโดยไม่ต้องกังวลเรื่องความเข้ากันได้ มีการเพิ่มคุณสมบัติใหม่ๆ เข้ามาอย่างต่อเนื่อง ในขณะที่ฟังก์ชันเดิมๆ ยังคงทำงานเหมือนเดิม -That had the benefit of never breaking existing code. But the downside was that any mistake or an imperfect decision made by JavaScript's creators got stuck in the language forever. +ซึ่งในแง่หนึ่งก็เป็นเรื่องดี เพราะไม่ทำให้โค้ดเดิมพังไป แต่ในอีกแง่ก็ทำให้ข้อผิดพลาดหรือการตัดสินใจออกแบบที่ไม่สมบูรณ์แบบของผู้พัฒนา JavaScript ถูกสืบทอดมาในภาษาเรื่อยๆ -This was the case until 2009 when ECMAScript 5 (ES5) appeared. It added new features to the language and modified some of the existing ones. To keep the old code working, most such modifications are off by default. You need to explicitly enable them with a special directive: `"use strict"`. +สถานการณ์เป็นแบบนั้นจนถึงปี 2009 เมื่อ ECMAScript 5 (ES5) เปิดตัว โดยมีการเพิ่มคุณสมบัติใหม่ และปรับปรุงบางส่วนที่มีอยู่เดิมให้ดีขึ้น แต่เพื่อให้โค้ดเก่ายังทำงานได้ การปรับปรุงส่วนใหญ่จึงถูกปิดไว้เป็นค่าเริ่มต้น ผู้ใช้ต้องเปิดใช้งานผ่าน directive พิเศษที่เรียกว่า `"use strict"` ## "use strict" -The directive looks like a string: `"use strict"` or `'use strict'`. When it is located at the top of a script, the whole script works the "modern" way. +Directive จะมีลักษณะคล้ายสตริง: `"use strict"` หรือ `'use strict'` เมื่อวางไว้ที่ต้นสคริปต์ ทั้งสคริปต์จะทำงานในโหมด "สมัยใหม่" -For example: +ตัวอย่างเช่น: ```js "use strict"; -// this code works the modern way +// โค้ดนี้จะทำงานในโหมดสมัยใหม่ ... ``` -Quite soon we're going to learn functions (a way to group commands), so let's note in advance that `"use strict"` can be put at the beginning of a function. Doing that enables strict mode in that function only. But usually people use it for the whole script. +เร็วๆ นี้เราจะได้เรียนรู้เรื่องฟังก์ชัน (การจัดกลุ่มคำสั่ง) ดังนั้นจึงขอบอกไว้ก่อนว่า `"use strict"` สามารถวางไว้ในฟังก์ชันได้ มันจะเปิดใช้งานโหมดเข้มงวดเฉพาะในฟังก์ชันนั้นเท่านั้น แต่โดยทั่วไปแล้วผู้คนจะใช้มันกับทั้งสคริปต์ -````warn header="Ensure that \"use strict\" is at the top" -Please make sure that `"use strict"` is at the top of your scripts, otherwise strict mode may not be enabled. +````warn header="ตรวจสอบให้แน่ใจว่า \"use strict\" อยู่ที่ต้นสคริปต์" +โปรดตรวจสอบให้แน่ใจว่า `"use strict"` อยู่ด้านบนสุดของสคริปต์ ไม่เช่นนั้นโหมดเข้มงวดอาจไม่ถูกเปิดใช้งาน -Strict mode isn't enabled here: +ดังเช่นในตัวอย่างนี้ โหมดเข้มงวดจะไม่ทำงาน: ```js no-strict alert("some code"); -// "use strict" below is ignored--it must be at the top +// "use strict" ด้านล่างถูกเพิกเฉย -- ต้องอยู่บรรทัดบนสุด "use strict"; -// strict mode is not activated +// โหมดเข้มงวดยังไม่เปิดใช้งาน ``` -Only comments may appear above `"use strict"`. +มีเพียงคอมเมนต์เท่านั้นที่สามารถปรากฏขึ้นเหนือ `"use strict"` ได้ ```` -```warn header="There's no way to cancel `use strict`" -There is no directive like `"no use strict"` that reverts the engine to old behavior. +```warn header="ไม่มีทางยกเลิก `use strict`" +ไม่มี directive อย่างเช่น `"no use strict"` ที่จะทำให้เอนจินย้อนกลับไปใช้พฤติกรรมแบบเก่า -Once we enter strict mode, there's no going back. +เมื่อเราเข้าสู่โหมดเข้มงวดแล้ว ก็ไม่มีทางย้อนกลับได้อีก ``` -## Browser console +## คอนโซลเบราว์เซอร์ -When you use a [developer console](info:devtools) to run code, please note that it doesn't `use strict` by default. +เมื่อคุณใช้ [คอนโซลนักพัฒนา](info:devtools) ในการรันโค้ด โปรดสังเกตว่ามันไม่ได้ `use strict` โดยค่าเริ่มต้น -Sometimes, when `use strict` makes a difference, you'll get incorrect results. +ในบางครั้ง เมื่อ `use strict` มีผลแตกต่างออกไป คุณอาจได้ผลลัพธ์ที่ไม่ถูกต้อง -So, how to actually `use strict` in the console? +แล้วจะใช้ `use strict` ในคอนโซลได้อย่างไร? -First, you can try to press `key:Shift+Enter` to input multiple lines, and put `use strict` on top, like this: +ก่อนอื่น คุณสามารถลองใช้ `key:Shift+Enter` เพื่อป้อนหลายบรรทัด แล้ววาง `use strict` ไว้ด้านบน แบบนี้: ```js -'use strict'; -// ...your code - +'use strict'; +// ...โค้ดของคุณ + ``` -It works in most browsers, namely Firefox and Chrome. +วิธีนี้ใช้ได้กับเบราว์เซอร์ส่วนใหญ่ เช่น Firefox และ Chrome -If it doesn't, e.g. in an old browser, there's an ugly, but reliable way to ensure `use strict`. Put it inside this kind of wrapper: +ถ้าไม่ได้ผล เช่นในเบราว์เซอร์รุ่นเก่า มีอีกทางที่อาจดูไม่สวยงามแต่ใช้งานได้ นั่นคือให้ห่อหุ้มมันด้วยฟังก์ชันแบบนี้: ```js (function() { @@ -72,18 +72,18 @@ If it doesn't, e.g. in an old browser, there's an ugly, but reliable way to ensu })() ``` -## Should we "use strict"? +## เราควรใช้ "use strict" หรือไม่? -The question may sound obvious, but it's not so. +คำถามอาจดูชัดเจน แต่จริงๆ แล้วไม่ได้ชัดเจนขนาดนั้น -One could recommend to start scripts with `"use strict"`... But you know what's cool? +ถ้าสอบถามความเห็นผู้อื่น บางคนอาจแนะนำให้เริ่มสคริปต์ทุกตัวด้วย `"use strict"`... แต่คุณรู้อะไรมั้ย? มีเรื่องที่น่าสนใจกว่านั้น -Modern JavaScript supports "classes" and "modules" - advanced language structures (we'll surely get to them), that enable `use strict` automatically. So we don't need to add the `"use strict"` directive, if we use them. +JavaScript สมัยใหม่รองรับ "classes" และ "modules" - โครงสร้างขั้นสูงของภาษา (เราจะต้องได้เรียนแน่นอน) ซึ่งจะเปิดใช้งาน `use strict` โดยอัตโนมัติ ดังนั้นเราจึงไม่จำเป็นต้องเพิ่ม directive `"use strict"` เองเมื่อใช้คุณสมบัติเหล่านี้ -**So, for now `"use strict";` is a welcome guest at the top of your scripts. Later, when your code is all in classes and modules, you may omit it.** +**ดังนั้น ตอนนี้ `"use strict"` คือส่วนเสริมที่ดีที่ควรใส่ไว้ต้นสคริปต์ แต่ในอนาคตเมื่อโค้ดทั้งหมดถูกเขียนเป็น classes และ modules เราก็อาจละมันไปได้** -As of now, we've got to know about `use strict` in general. +ถึงตอนนี้เราก็ได้มีความรู้เบื้องต้นเกี่ยวกับ `use strict` แล้ว -In the next chapters, as we learn language features, we'll see the differences between the strict and old modes. Luckily, there aren't many and they actually make our lives better. +ในบทต่อๆ ไป เมื่อเราเรียนรู้คุณสมบัติต่างๆ ของภาษา เราจะเห็นความแตกต่างระหว่างโหมดเข้มงวดและโหมดปกติ โชคดีที่มันไม่ได้แตกต่างกันมากนัก และจริงๆ แล้วโหมดเข้มงวดทำให้ชีวิตเราสะดวกขึ้นด้วยซ้ำ -All examples in this tutorial assume strict mode unless (very rarely) specified otherwise. +ทุกตัวอย่างโค้ดในบทเรียนนี้จะถือว่าใช้โหมดเข้มงวด ยกเว้น (ซึ่งพบได้น้อยมาก) ที่ระบุเป็นอย่างอื่น diff --git a/1-js/02-first-steps/04-variables/1-hello-variables/solution.md b/1-js/02-first-steps/04-variables/1-hello-variables/solution.md index 9249e1c84..d2b9ca9ff 100644 --- a/1-js/02-first-steps/04-variables/1-hello-variables/solution.md +++ b/1-js/02-first-steps/04-variables/1-hello-variables/solution.md @@ -1,4 +1,4 @@ -In the code below, each line corresponds to the item in the task list. +โค้ดด้านล่างจะสัมพันธ์กับ รายการใน task list ```js run let admin, name; // can declare two variables at once diff --git a/1-js/02-first-steps/04-variables/1-hello-variables/task.md b/1-js/02-first-steps/04-variables/1-hello-variables/task.md index 84f009e8c..564023a59 100644 --- a/1-js/02-first-steps/04-variables/1-hello-variables/task.md +++ b/1-js/02-first-steps/04-variables/1-hello-variables/task.md @@ -2,9 +2,9 @@ importance: 2 --- -# Working with variables +# เล่นกับตัวแปร -1. Declare two variables: `admin` and `name`. -2. Assign the value `"John"` to `name`. -3. Copy the value from `name` to `admin`. -4. Show the value of `admin` using `alert` (must output "John"). +1. สร้างตัวแปรมาสองตัวชื่อ `admin` และ `name` +2. กำหนดค่าให้ตัวแปรทั้งสองคือ `"John"` ไปที่ `name` +3. คัดลอกค่าจาก `name` ไปที่ `admin` +4. แสดงค่าที่เก็บใน `admin` โดยใช้ `alert` (ผลลัพธ์จะต้องออกมาเป็น "John") diff --git a/1-js/02-first-steps/04-variables/2-declare-variables/solution.md b/1-js/02-first-steps/04-variables/2-declare-variables/solution.md index 392f4e26f..5db98e945 100644 --- a/1-js/02-first-steps/04-variables/2-declare-variables/solution.md +++ b/1-js/02-first-steps/04-variables/2-declare-variables/solution.md @@ -1,21 +1,21 @@ -## The variable for our planet +## ชื่อตัวแปรที่เก็บค่าดาวโลกไว้ -That's simple: +ก็ง่ายมาก ```js let ourPlanetName = "Earth"; ``` -Note, we could use a shorter name `planet`, but it might not be obvious what planet it refers to. It's nice to be more verbose. At least until the variable isNotTooLong. +จำไว้ว่า ที่จริงเราควรใช้ชื่อที่สั้นอย่าง `planet` แต่ตัวแปรก็ยังไม่ชัดเจนว่าจะสื่อถึงดาวเคราะห์ดวงไหน เราจะตั้งชื่อให้ยาวไปอีกสักนิดเพื่อการสื่อความ ตราบใดที่ชื่อตัวแปรไม่ได้ isNotTooLong -## The name of the current visitor +## ชื่อตัวแปรที่เก็บชื่อผู้เยี่ยมชมเว็บไซต์ปัจจุบัน ```js let currentUserName = "John"; ``` -Again, we could shorten that to `userName` if we know for sure that the user is current. +ที่จริงเราจะควรใช้ชื่อที่สั้นกว่านี้ อย่างเช่น `userName` หากเรารู้แน่นอนว่านี่คือผู้ใช้คนปัจจุบัน -Modern editors and autocomplete make long variable names easy to write. Don't save on them. A name with 3 words in it is fine. +ใน editors ใหม่ๆ จะมาพร้อมกับฟีเจอร์ autocomplete ที่ไม่ต้องเสียเวลาพิมพ์ชื่อตัวแปรยาวๆ -And if your editor does not have proper autocompletion, get [a new one](/code-editors). +และหาก editors ที่คุณใช้ดูยังไม่มีฟีเจอร์นี้ เราขอแนะนำให้[หามาใช้สักตัว](/code-editors) diff --git a/1-js/02-first-steps/04-variables/2-declare-variables/task.md b/1-js/02-first-steps/04-variables/2-declare-variables/task.md index f364badf4..dcb077d96 100644 --- a/1-js/02-first-steps/04-variables/2-declare-variables/task.md +++ b/1-js/02-first-steps/04-variables/2-declare-variables/task.md @@ -2,7 +2,7 @@ importance: 3 --- -# Giving the right name +# จงมอบนามที่ถูกต้อง -1. Create a variable with the name of our planet. How would you name such a variable? -2. Create a variable to store the name of a current visitor to a website. How would you name that variable? +1. จะตั้งชื่อตัวแปรที่เก็บค่า "Earth" ไว้ว่าอะไรดี +2. จะตั้งชื่อตัวแปรที่เก็บชื่อผู้เยี่ยมชมเว็บไซต์ตอนนี้ว่าอะไรดี diff --git a/1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md b/1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md index acd643fde..c35e5e902 100644 --- a/1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md +++ b/1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md @@ -1,5 +1,5 @@ -We generally use upper case for constants that are "hard-coded". Or, in other words, when the value is known prior to execution and directly written into the code. +โดยปกติเราใช้ตัวพิมพ์ใหญ่สำหรับตัวแปรที่เก็บค่าคงที่ที่เป็น "ฮาร์ดโค้ด" -In this code, `birthday` is exactly like that. So we could use the upper case for it. +ในโค้ดนี้ตัวแปร `birthday` เก็บค่าวันเกิดเอาไว้ ซึ่งพิจารณาได้ว่าเป็น "ฮาร์ดโค้ด" เราเลยใช้ชื่อตัวแปรเป็นตัวพิมพ์ใหญ่ -In contrast, `age` is evaluated in run-time. Today we have one age, a year after we'll have another one. It is constant in a sense that it does not change through the code execution. But it is a bit "less of a constant" than `birthday`: it is calculated, so we should keep the lower case for it. +แต่ตัวแปร `age` จะมีค่าก็ต่อเมื่อโค้ดนี้ทำงาน โดยปีนี้เราจะได้อายุค่าหนึ่ง ปีหน้าก็เป็นอีกค่าหนึ่ง เนื่องจากตัวแปร `age` จะมีค่าหลังจากถูกคำนวณแล้ว ในแง่ความเป็นค่าคงที่แล้ว จึงมีความเป็นค่าคงที่น้อยกว่าตัวแปร `birthday` diff --git a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md index f3c208a74..85653e80e 100644 --- a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md +++ b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md @@ -2,9 +2,9 @@ importance: 4 --- -# Uppercase const? +# const แบบพิมพ์ใหญ่ -Examine the following code: +ลองพิจารณาจากโค้ดดังต่อไปนี้ ```js const birthday = '18.04.1982'; @@ -12,11 +12,15 @@ const birthday = '18.04.1982'; const age = someCode(birthday); ``` +<<<<<<< HEAD +เรามีตัวแปร `birthday` และ `age` ที่จะถูกคำนวณจากค่าเริ่มต้นอย่าง `birthday` ด้วยความช่วยเหลือจากฟังก์ชั่น `someCode` (ในตอนนี้ยังไม่ต้องรู้จักฟังก์ชั่น เพราะยังไม่ใช่ประเด็นในตอนนี้) +======= Here we have a constant `birthday` for the date, and also the `age` constant. The `age` is calculated from `birthday` using `someCode()`, which means a function call that we didn't explain yet (we will soon!), but the details don't matter here, the point is that `age` is calculated somehow based on the `birthday`. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Would it be right to use upper case for `birthday`? For `age`? Or even for both? +จะให้ชื่อตัวแปรไหนเป็น ตัวพิมพ์เล็ก หรือ ตัวใหญ่ดีตัวแปร `birthday` ดีไหม? หรือตัวแปร `age` หรือจะทั้งคู่ดีละ ```js const BIRTHDAY = '18.04.1982'; // make birthday uppercase? diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md index e91d0ea7e..2fb1ff063 100644 --- a/1-js/02-first-steps/04-variables/article.md +++ b/1-js/02-first-steps/04-variables/article.md @@ -1,274 +1,326 @@ -# Variables +# ตัวแปร -Most of the time, a JavaScript application needs to work with information. Here are two examples: -1. An online shop -- the information might include goods being sold and a shopping cart. -2. A chat application -- the information might include users, messages, and much more. +ในการพัฒนาแอปพลิเคชัน JavaScript ส่วนใหญ่ เรามักจะต้องทำงานกับข้อมูล ยกตัวอย่างเช่น +1. ร้านค้าออนไลน์ -- ข้อมูลอาจประกอบด้วยสินค้าที่จำหน่ายและตะกร้าสินค้า +2. แอปพลิเคชันแชท -- ข้อมูลอาจประกอบด้วยผู้ใช้ ข้อความ และอื่นๆ อีกมากมาย -Variables are used to store this information. +ตัวแปรถูกใช้เพื่อจัดเก็บข้อมูลเหล่านี้ -## A variable +## ตัวแปรคืออะไร -A [variable](https://en.wikipedia.org/wiki/Variable_(computer_science)) is a "named storage" for data. We can use variables to store goodies, visitors, and other data. +[ตัวแปร](https://en.wikipedia.org/wiki/Variable_(computer_science)) คือ "พื้นที่จัดเก็บข้อมูลที่มีชื่อกำกับ" เราสามารถใช้ตัวแปรเพื่อเก็บสินค้า ข้อมูลผู้เยี่ยมชม และข้อมูลอื่นๆ ได้ -To create a variable in JavaScript, use the `let` keyword. +ในการสร้างตัวแปรใน JavaScript ให้ใช้คีย์เวิร์ด `let` -The statement below creates (in other words: *declares*) a variable with the name "message": +คำสั่งด้านล่างจะสร้าง (หรือที่เรียกอีกอย่างว่า *ประกาศ*) ตัวแปรที่มีชื่อว่า "message": ```js let message; ``` -Now, we can put some data into it by using the assignment operator `=`: +ตอนนี้เราสามารถใส่ข้อมูลลงในตัวแปรได้ด้วยการใช้เครื่องหมาย `=` หรือที่เรียกว่าตัวดำเนินการกำหนดค่า (assignment operator): ```js let message; *!* -message = 'Hello'; // store the string 'Hello' in the variable named message +message = 'สวัสดี'; // เก็บข้อความ 'สวัสดี' ในตัวแปรที่ชื่อว่า message */!* ``` -The string is now saved into the memory area associated with the variable. We can access it using the variable name: +ข้อความนี้จะถูกบันทึกลงในพื้นที่หน่วยความจำที่สัมพันธ์กับตัวแปร และเราสามารถเข้าถึงข้อมูลนี้ได้ด้วยการอ้างอิงชื่อตัวแปร: ```js run let message; -message = 'Hello!'; +message = 'สวัสดี!'; *!* -alert(message); // shows the variable content +alert(message); // แสดงค่าในตัวแปร */!* ``` -To be concise, we can combine the variable declaration and assignment into a single line: +เพื่อความกระชับ เราสามารถรวมการประกาศตัวแปรและกำหนดค่าเริ่มต้นไว้ในบรรทัดเดียวกันได้: ```js run -let message = 'Hello!'; // define the variable and assign the value +let message = 'สวัสดี!'; // ประกาศตัวแปรและกำหนดค่าในคำสั่งเดียว -alert(message); // Hello! +alert(message); // สวัสดี! ``` -We can also declare multiple variables in one line: +นอกจากนี้ เรายังสามารถประกาศตัวแปรหลายตัวในบรรทัดเดียวได้ด้วย: ```js no-beautify -let user = 'John', age = 25, message = 'Hello'; +let user = 'จอห์น', age = 25, message = 'สวัสดี'; ``` -That might seem shorter, but we don't recommend it. For the sake of better readability, please use a single line per variable. +วิธีนี้อาจจะดูสั้นกระชับดี แต่เราไม่แนะนำให้ใช้ เพื่อความสะดวกในการอ่านโค้ด ควรประกาศตัวแปรแต่ละตัวแยกเป็นคนละบรรทัดจะดีกว่า -The multiline variant is a bit longer, but easier to read: +แบบนี้อาจยาวกว่าเล็กน้อย แต่อ่านง่ายขึ้นมาก: ```js -let user = 'John'; +let user = 'จอห์น'; let age = 25; -let message = 'Hello'; +let message = 'สวัสดี'; ``` +<<<<<<< HEAD +บางคนยังชอบประกาศตัวแปรหลายตัวแบบหลายบรรทัดแบบนี้: +======= Some people also define multiple variables in this multiline style: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js no-beautify -let user = 'John', +let user = 'จอห์น', age = 25, - message = 'Hello'; + message = 'สวัสดี'; ``` -...Or even in the "comma-first" style: +หรือแม้กระทั่งเขียนในรูปแบบ "เริ่มต้นด้วยเครื่องหมายจุลภาค": ```js no-beautify -let user = 'John' +let user = 'จอห์น' , age = 25 - , message = 'Hello'; + , message = 'สวัสดี'; ``` -Technically, all these variants do the same thing. So, it's a matter of personal taste and aesthetics. +ในเชิงเทคนิคแล้ว ตัวแปรทั้งหมดที่ยกตัวอย่างมาทำงานในลักษณะเดียวกัน จึงเป็นเรื่องของรสนิยมและความชอบส่วนตัว -````smart header="`var` instead of `let`" -In older scripts, you may also find another keyword: `var` instead of `let`: +````smart header="`var` กับ `let`" +ในสคริปต์เก่าๆ คุณอาจเจอการใช้คีย์เวิร์ด `var` แทน `let` ในการประกาศตัวแปร: ```js -*!*var*/!* message = 'Hello'; +*!*var*/!* message = 'สวัสดี'; ``` +<<<<<<< HEAD +คีย์เวิร์ด `var` นั้น*เกือบจะ*เหมือนกับ `let` คือใช้ประกาศตัวแปร แต่จะมีความแตกต่างเล็กน้อยในสไตล์ที่ค่อนข้าง "เชย" + +ความแตกต่างระหว่าง `let` กับ `var` นั้นไม่ใช่ประเด็นสำคัญสำหรับเราในตอนนี้ เราจะกล่าวถึงรายละเอียดในบทเรียน + +โดยทั่วไปแล้ว ในโค้ด JavaScript สมัยใหม่เรามักใช้ `let` ในการประกาศตัวแปร ส่วนการใช้ `var` ถือเป็นวิธีการแบบเดิมที่ปัจจุบันไม่เป็นที่นิยมแล้ว +======= The `var` keyword is *almost* the same as `let`. It also declares a variable but in a slightly different, "old-school" way. There are subtle differences between `let` and `var`, but they do not matter to us yet. We'll cover them in detail in the chapter . +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```` -## A real-life analogy +# การเปรียบเทียบกับสถานการณ์ในชีวิตจริง -We can easily grasp the concept of a "variable" if we imagine it as a "box" for data, with a uniquely-named sticker on it. +เราสามารถเข้าใจแนวคิดของ "ตัวแปร" ได้ง่ายขึ้น ถ้าลองนึกภาพว่ามันเป็น "กล่อง" ไว้ใส่ข้อมูล โดยมีสติกเกอร์ชื่อเฉพาะติดอยู่ +<<<<<<< HEAD +ยกตัวอย่างเช่น ตัวแปร `message` จะเปรียบได้กับกล่องที่มีป้ายชื่อ `"message"` และมีค่า `"สวัสดี!"` ข้างใน: +======= For instance, the variable `message` can be imagined as a box labelled `"message"` with the value `"Hello!"` in it: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ![](variable.svg) -We can put any value in the box. +เราสามารถใส่ค่าอะไรก็ได้ลงในกล่องนี้ +และเปลี่ยนค่าได้ตามใจชอบ: + +<<<<<<< HEAD +======= We can also change it as many times as we want: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js run let message; -message = 'Hello!'; +message = 'สวัสดี!'; -message = 'World!'; // value changed +message = 'ชาวโลก!'; // เปลี่ยนค่าแล้ว alert(message); ``` -When the value is changed, the old data is removed from the variable: +เวลาเปลี่ยนค่า ข้อมูลเก่าจะถูกนำออกจากตัวแปรไป: ![](variable-change.svg) -We can also declare two variables and copy data from one into the other. +นอกจากนี้ เรายังสามารถประกาศตัวแปรสองตัว แล้วคัดลอกข้อมูลจากตัวหนึ่งไปอีกตัวหนึ่งได้ด้วย ```js run -let hello = 'Hello world!'; +let hello = 'สวัสดีชาวโลก!'; let message; *!* -// copy 'Hello world' from hello into message +// คัดลอก 'สวัสดีชาวโลก!' จาก hello มาเก็บใน message message = hello; */!* -// now two variables hold the same data -alert(hello); // Hello world! -alert(message); // Hello world! +// ตอนนี้ตัวแปรทั้งสองมีข้อมูลชุดเดียวกัน +alert(hello); // สวัสดีชาวโลก! +alert(message); // สวัสดีชาวโลก! ``` -````warn header="Declaring twice triggers an error" -A variable should be declared only once. +````warn header="การประกาศตัวแปรซ้ำจะเกิดข้อผิดพลาด" +ควรประกาศตัวแปรเพียงครั้งเดียวเท่านั้น -A repeated declaration of the same variable is an error: +หากประกาศตัวแปรเดิมซ้ำอีก จะถือเป็นข้อผิดพลาด: ```js run -let message = "This"; +let message = "นี่"; -// repeated 'let' leads to an error -let message = "That"; // SyntaxError: 'message' has already been declared +// ประกาศ 'let' ซ้ำ ทำให้เกิด error +let message = "นั่น"; // SyntaxError: 'message' ถูกประกาศไปแล้ว ``` -So, we should declare a variable once and then refer to it without `let`. + +ดังนั้น เราควรประกาศตัวแปรแค่ครั้งเดียว จากนั้นก็อ้างอิงถึงมันได้เลยโดยไม่ต้องมี `let` อีก ```` +<<<<<<< HEAD +```smart header="ภาษาการเขียนโปรแกรมแบบฟังก์ชัน" +น่าสนใจว่า มีภาษาโปรแกรมที่เรียกว่า [ฟังก์ชันเชิงบริสุทธิ์](https://en.wikipedia.org/wiki/Purely_functional_programming) เช่น [Haskell](https://en.wikipedia.org/wiki/Haskell) ซึ่งห้ามไม่ให้เปลี่ยนค่าตัวแปรเด็ดขาด +======= ```smart header="Functional languages" It's interesting to note that there exist so-called [pure functional](https://en.wikipedia.org/wiki/Purely_functional_programming) programming languages, such as [Haskell](https://en.wikipedia.org/wiki/Haskell), that forbid changing variable values. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -In such languages, once the value is stored "in the box", it's there forever. If we need to store something else, the language forces us to create a new box (declare a new variable). We can't reuse the old one. +ในภาษาเหล่านี้ เมื่อเก็บค่าใส่ "กล่อง" ไปแล้ว มันจะอยู่ในนั้นตลอดกาล หากต้องการเก็บข้อมูลอย่างอื่น ภาษาจะบังคับให้เราต้องสร้างกล่องใหม่ (ประกาศตัวแปรใหม่) จะนำกล่องเก่ามาใช้ใหม่ไม่ได้ +<<<<<<< HEAD +ถึงแม้พอแรกอาจฟังดูแปลกๆ แต่ภาษาพวกนี้ก็มีความสามารถในการพัฒนาโปรแกรมจริงจังได้นะ ยิ่งไปกว่านั้น ในบางด้านอย่างการประมวลผลแบบขนาน ข้อจำกัดนี้กลับให้ประโยชน์บางอย่างเสียด้วยซ้ำ +======= Though it may seem a little odd at first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation confers certain benefits. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ``` -## Variable naming [#variable-naming] +## การตั้งชื่อตัวแปร [#variable-naming] -There are two limitations on variable names in JavaScript: +ในภาษา JavaScript มีข้อจำกัด 2 ประการในการตั้งชื่อตัวแปร: -1. The name must contain only letters, digits, or the symbols `$` and `_`. -2. The first character must not be a digit. +1. ชื่อต้องประกอบด้วยตัวอักษร ตัวเลข หรือสัญลักษณ์ `$` และ `_` เท่านั้น +2. ตัวอักษรตัวแรกต้องไม่ใช่ตัวเลข -Examples of valid names: +ตัวอย่างชื่อที่ใช้ได้: ```js let userName; let test123; ``` -When the name contains multiple words, [camelCase](https://en.wikipedia.org/wiki/CamelCase) is commonly used. That is: words go one after another, each word except first starting with a capital letter: `myVeryLongName`. +เมื่อชื่อประกอบด้วยหลายคำ มักนิยมใช้รูปแบบ [camelCase](https://en.wikipedia.org/wiki/CamelCase) นั่นคือเขียนคำต่อกันเรื่อยๆ โดยขึ้นต้นคำแรกด้วยตัวพิมพ์เล็ก ส่วนคำถัดๆ ไปให้ขึ้นต้นด้วยตัวพิมพ์ใหญ่ เช่น `myVeryLongName` -What's interesting -- the dollar sign `'$'` and the underscore `'_'` can also be used in names. They are regular symbols, just like letters, without any special meaning. +ที่น่าสนใจคือ เครื่องหมายดอลลาร์ `'$'` และอันเดอร์สกอร์ `'_'` ก็สามารถใช้เป็นส่วนหนึ่งของชื่อได้ โดยมันเป็นแค่สัญลักษณ์ธรรมดาเหมือนตัวอักษร ไม่ได้มีความหมายพิเศษอะไร -These names are valid: +ชื่อเหล่านี้ใช้ได้: ```js run untrusted -let $ = 1; // declared a variable with the name "$" -let _ = 2; // and now a variable with the name "_" +let $ = 1; // ประกาศตัวแปรชื่อ "$" +let _ = 2; // และนี่ตัวแปรชื่อ "_" alert($ + _); // 3 ``` -Examples of incorrect variable names: +ตัวอย่างชื่อตัวแปรที่ใช้ไม่ได้: ```js no-beautify -let 1a; // cannot start with a digit +let 1a; // ห้ามขึ้นต้นด้วยตัวเลข -let my-name; // hyphens '-' aren't allowed in the name +let my-name; // เครื่องหมายขีด '-' ไม่อนุญาตให้ใช้ในชื่อ ``` +<<<<<<< HEAD +```smart header="ตัวพิมพ์ใหญ่-เล็กมีผล" +ตัวแปร `apple` กับ `APPLE` ถือเป็นคนละตัวกัน +``` + +```smart header="อักษรที่ไม่ใช่ภาษาอังกฤษใช้ได้ แต่ไม่แนะนำ" +เราสามารถใช้ภาษาอื่นๆ ได้ รวมถึงอักษรภาษารัสเซีย อักษรจีน หรืออื่นๆ เช่น: +======= ```smart header="Case matters" Variables named `apple` and `APPLE` are two different variables. ``` ````smart header="Non-Latin letters are allowed, but not recommended" It is possible to use any language, including Cyrillic letters, Chinese logograms and so on, like this: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js let имя = '...'; let 我 = '...'; ``` +<<<<<<< HEAD +ในทางเทคนิคแล้ว ตัวอย่างข้างบนไม่มีข้อผิดพลาด การตั้งชื่อแบบนั้นใช้ได้ แต่เรามีข้อตกลงสากลว่าควรใช้ภาษาอังกฤษในการตั้งชื่อตัวแปร เพราะถึงแม้จะเป็นสคริปต์สั้นๆ แต่ก็อาจจะมีชีวิตอยู่ได้นานมาก และในอนาคตอาจมีคนจากประเทศอื่นจำเป็นต้องเข้ามาอ่านมันก็เป็นได้ +``` +======= Technically, there is no error here. Such names are allowed, but there is an international convention to use English in variable names. Even if we're writing a small script, it may have a long life ahead. People from other countries may need to read it sometime. ```` +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -````warn header="Reserved names" -There is a [list of reserved words](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords), which cannot be used as variable names because they are used by the language itself. +```warn header="ชื่อที่สงวนไว้" +มี[รายการคำสงวน](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords) ที่ไม่อนุญาตให้นำมาตั้งเป็นชื่อตัวแปร เพราะมันถูกสงวนไว้ใช้โดยตัวภาษาเอง -For example: `let`, `class`, `return`, and `function` are reserved. +ตัวอย่างเช่น: `let`, `class`, `return` และ `function` เป็นคำสงวน -The code below gives a syntax error: +โค้ดด้านล่างจะเกิด syntax error: ```js run no-beautify -let let = 5; // can't name a variable "let", error! -let return = 5; // also can't name it "return", error! +let let = 5; // ไม่สามารถตั้งชื่อตัวแปรว่า "let" เพราะเป็นคำสงวน เกิด error! +let return = 5; // เช่นเดียวกัน ห้ามตั้งชื่อเป็น "return" เกิด error! +``` ``` -```` -````warn header="An assignment without `use strict`" +```warn header="การกำหนดค่าโดยไม่ใช้ `use strict`" -Normally, we need to define a variable before using it. But in the old times, it was technically possible to create a variable by a mere assignment of the value without using `let`. This still works now if we don't put `use strict` in our scripts to maintain compatibility with old scripts. +โดยปกติแล้วเราต้องประกาศตัวแปรก่อนใช้งาน แต่ในสมัยก่อนมีช่องโหว่ทางเทคนิคที่ทำให้สร้างตัวแปรได้โดยแค่กำหนดค่าให้มันเลย โดยไม่ต้องใช้ `let` ซึ่งยังคงใช้ได้อยู่ในปัจจุบันหากไม่ใส่ `use strict` ลงในสคริปต์ เพื่อรักษาความเข้ากันได้กับสคริปต์เก่าๆ ```js run no-strict -// note: no "use strict" in this example +// หมายเหตุ: ไม่มีการใช้ "use strict" ในตัวอย่างนี้ -num = 5; // the variable "num" is created if it didn't exist +num = 5; // ถ้าไม่มีตัวแปร "num" มันจะถูกสร้างขึ้นโดยอัตโนมัติ alert(num); // 5 ``` -This is a bad practice and would cause an error in strict mode: +วิธีนี้ถือเป็นแนวปฏิบัติที่ไม่ดี และจะเกิดข้อผิดพลาดในโหมดเข้มงวด (strict mode): ```js "use strict"; *!* -num = 5; // error: num is not defined +num = 5; // error: ตัวแปร num ไม่ได้ถูกประกาศไว้ก่อน */!* ``` -```` -## Constants +## ค่าคงที่ (Constants) -To declare a constant (unchanging) variable, use `const` instead of `let`: +เพื่อประกาศตัวแปรค่าคงที่ (ไม่เปลี่ยนแปลงค่า) ให้ใช้ `const` แทน `let`: ```js const myBirthday = '18.04.1982'; ``` -Variables declared using `const` are called "constants". They cannot be reassigned. An attempt to do so would cause an error: +ตัวแปรที่ประกาศด้วย `const` จะเรียกว่า "ค่าคงที่" ซึ่งไม่สามารถกำหนดค่าใหม่ได้ หากพยายามทำเช่นนั้นจะเกิดข้อผิดพลาด: ```js run const myBirthday = '18.04.1982'; -myBirthday = '01.01.2001'; // error, can't reassign the constant! +myBirthday = '01.01.2001'; // error เพราะไม่สามารถกำหนดค่าใหม่ให้ค่าคงที่ได้! ``` +<<<<<<< HEAD +เมื่อโปรแกรมเมอร์มั่นใจว่าตัวแปรจะไม่มีวันเปลี่ยนแปลงค่า ก็สามารถประกาศเป็นค่าคงที่ด้วย `const` เพื่อการันตีและสื่อสารข้อเท็จจริงดังกล่าวให้ทุกคนรับทราบ + +### ค่าคงที่ที่เขียนด้วยตัวพิมพ์ใหญ่ +======= When a programmer is sure that a variable will never change, they can declare it with `const` to guarantee and communicate that fact to everyone. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -### Uppercase constants +ในทางปฏิบัติ มักนิยมใช้ค่าคงที่เป็นนามแทนสำหรับค่าที่จำยาก ซึ่งทราบค่าตายตัวก่อนการประมวลผลโปรแกรมแล้ว +<<<<<<< HEAD +ค่าคงที่ลักษณะนี้มักตั้งชื่อโดยใช้ตัวพิมพ์ใหญ่และอันเดอร์สกอร์ +======= There is a widespread practice to use constants as aliases for difficult-to-remember values that are known before execution. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Such constants are named using capital letters and underscores. - -For instance, let's make constants for colors in so-called "web" (hexadecimal) format: +ยกตัวอย่างเช่น ลองสร้างค่าคงที่แทนรหัสสีในฟอร์แมต "web" (เขียนเป็นเลขฐานสิบหก): ```js run const COLOR_RED = "#F00"; @@ -276,70 +328,96 @@ const COLOR_GREEN = "#0F0"; const COLOR_BLUE = "#00F"; const COLOR_ORANGE = "#FF7F00"; -// ...when we need to pick a color +// เมื่อต้องการเลือกสีใดสีหนึ่ง let color = COLOR_ORANGE; alert(color); // #FF7F00 ``` -Benefits: +ข้อดี: -- `COLOR_ORANGE` is much easier to remember than `"#FF7F00"`. -- It is much easier to mistype `"#FF7F00"` than `COLOR_ORANGE`. -- When reading the code, `COLOR_ORANGE` is much more meaningful than `#FF7F00`. +- `COLOR_ORANGE` จำได้ง่ายกว่า `"#FF7F00"` มาก +- พิมพ์ผิดเป็น `"#FF7F00"` ได้ง่ายกว่า `COLOR_ORANGE` +- เวลาอ่านโค้ด `COLOR_ORANGE` สื่อความหมายได้ชัดเจนกว่า `#FF7F00` -When should we use capitals for a constant and when should we name it normally? Let's make that clear. +แล้วเราควรใช้ตัวพิมพ์ใหญ่กับค่าคงที่เมื่อไหร่ และควรตั้งชื่อปกติเมื่อไหร่? ลองมาทำความเข้าใจกัน +<<<<<<< HEAD +คำว่า "ค่าคงที่" หมายถึงค่าของตัวแปรจะไม่มีวันเปลี่ยนแปลงเท่านั้น แต่ค่าคงที่บางตัวเป็นที่รู้จักก่อนการประมวลผล (เช่นค่าฐานสิบหกของสีแดง) ส่วนค่าคงที่อีกประเภทคือถูก*คำนวณ*ระหว่างรันไทม์ ในช่วงการประมวลผล แต่จะไม่เปลี่ยนแปลงหลังจากกำหนดค่าไปแล้ว + +ตัวอย่างเช่น: + +======= Being a "constant" just means that a variable's value never changes. But some constants are known before execution (like a hexadecimal value for red) and some constants are *calculated* in run-time, during the execution, but do not change after their initial assignment. For instance: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js -const pageLoadTime = /* time taken by a webpage to load */; +const pageLoadTime = /* เวลาที่ใช้ในการโหลดเว็บเพจ */; ``` +<<<<<<< HEAD +ค่าของ `pageLoadTime` ไม่เป็นที่ทราบก่อนโหลดเพจ ดังนั้นจึงตั้งชื่อแบบปกติ แต่ถึงอย่างนั้นมันก็ยังเป็นค่าคงที่ เพราะไม่มีการเปลี่ยนแปลงค่าหลังจากกำหนดไปแล้ว + +หรือพูดอีกอย่างคือ ค่าคงที่ที่ตั้งชื่อด้วยตัวพิมพ์ใหญ่จะใช้เป็นเพียงแค่นามแทนสำหรับค่าที่ "ฮาร์ดโค้ด" เข้าไปโดยตรงเท่านั้น +======= The value of `pageLoadTime` is not known before the page load, so it's named normally. But it's still a constant because it doesn't change after the assignment. In other words, capital-named constants are only used as aliases for "hard-coded" values. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +## ตั้งชื่อให้ถูกต้อง -## Name things right +เมื่อพูดถึงตัวแปร มีอีกเรื่องสำคัญมากที่ต้องคำนึงถึง นั่นคือ -Talking about variables, there's one more extremely important thing. +ชื่อตัวแปรควรมีความหมายที่ชัดเจน เข้าใจง่าย สามารถอธิบายข้อมูลที่เก็บอยู่ภายในได้ -A variable name should have a clean, obvious meaning, describing the data that it stores. +<<<<<<< HEAD +การตั้งชื่อตัวแปรถือเป็นหนึ่งในทักษะที่สำคัญและซับซ้อนที่สุดในการเขียนโปรแกรม เพียงแค่กวาดตามองผ่านชื่อตัวแปร ก็สามารถบอกได้แล้วว่าโค้ดนั้นเขียนโดยมือใหม่หรือนักพัฒนาที่มีประสบการณ์ +ในโปรเจ็กต์จริง เรามักใช้เวลาส่วนใหญ่ไปกับการแก้ไขและต่อยอดโค้ดเดิมที่มีอยู่แล้ว มากกว่าการเขียนโค้ดใหม่ล้วนๆ จากศูนย์ เมื่อต้องย้อนกลับไปดูโค้ดหลังจากไปทำอย่างอื่นสักพัก การมีข้อมูลที่ตั้งชื่อตัวแปรไว้อย่างดีจะช่วยให้เราหาสิ่งที่ต้องการได้ง่ายขึ้นมาก หรือพูดอีกอย่างคือ เมื่อตัวแปรมีชื่อที่ดีนั่นเอง +======= Variable naming is one of the most important and complex skills in programming. A glance at variable names can reveal which code was written by a beginner versus an experienced developer. In a real project, most of the time is spent modifying and extending an existing code base rather than writing something completely separate from scratch. When we return to some code after doing something else for a while, it's much easier to find information that is well-labelled. Or, in other words, when the variables have good names. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Please spend time thinking about the right name for a variable before declaring it. Doing so will repay you handsomely. +ดังนั้น ควรใช้เวลาคิดพิจารณาชื่อที่เหมาะสมให้ตัวแปร ก่อนที่จะประกาศใช้มัน การทำเช่นนี้จะคุ้มค่าเป็นอย่างมากในภายหลัง -Some good-to-follow rules are: +ต่อไปนี้คือกฎที่ควรนำไปปฏิบัติ: +<<<<<<< HEAD +- ใช้ชื่อที่มนุษย์อ่านเข้าใจได้ เช่น `userName` หรือ `shoppingCart` +- หลีกเลี่ยงการใช้คำย่อหรือชื่อสั้นๆ อย่าง `a`, `b` หรือ `c` ยกเว้นว่าคุณมั่นใจว่ากำลังทำอะไรอยู่ +- ตั้งชื่อให้อธิบายได้ชัดเจนที่สุดและกระชับ ตัวอย่างชื่อที่ไม่ดี ได้แก่ `data` และ `value` เพราะไม่ได้สื่อความหมายอะไร ยกเว้นบริบทของโค้ดจะบ่งชี้ชัดว่าตัวแปรนั้นหมายถึงข้อมูลหรือค่าใด +- ตกลงใช้ศัพท์เฉพาะกันภายในทีมและในใจของคุณเอง ถ้าเรียกผู้เยี่ยมชมเว็บว่า "user" เราก็ควรตั้งชื่อตัวแปรที่เกี่ยวข้องว่า `currentUser` หรือ `newUser` แทนที่จะเป็น `currentVisitor` หรือ `newManInTown` +======= - Use human-readable names like `userName` or `shoppingCart`. - Stay away from abbreviations or short names like `a`, `b`, and `c`, unless you know what you're doing. - Make names maximally descriptive and concise. Examples of bad names are `data` and `value`. Such names say nothing. It's only okay to use them if the context of the code makes it exceptionally obvious which data or value the variable is referencing. - Agree on terms within your team and in your mind. If a site visitor is called a "user" then we should name related variables `currentUser` or `newUser` instead of `currentVisitor` or `newManInTown`. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Sounds simple? Indeed it is, but creating descriptive and concise variable names in practice is not. Go for it. +ฟังดูง่ายมั้ย แต่ในทางปฏิบัติ การสร้างชื่อตัวแปรที่สื่อความหมายและกระชับไม่ใช่เรื่องง่ายเลย ลองทำดูนะ -```smart header="Reuse or create?" -And the last note. There are some lazy programmers who, instead of declaring new variables, tend to reuse existing ones. +```smart header="ใช้ซ้ำหรือสร้างใหม่" +และอีกหนึ่งข้อสังเกต มีนักเขียนโปรแกรมบางส่วนที่ขี้เกียจ ชอบเอาตัวแปรที่มีอยู่แล้วมาใช้ซ้ำ แทนที่จะประกาศตัวแปรใหม่ -As a result, their variables are like boxes into which people throw different things without changing their stickers. What's inside the box now? Who knows? We need to come closer and check. +ผลที่ได้ก็คือ ตัวแปรของพวกเขาจะเหมือนกล่องที่มีคนเอาของต่างๆ ใส่ลงไป โดยไม่เปลี่ยนป้ายข้างนอก แล้วตอนนี้ในกล่องมีอะไรบ้าง? ไม่มีใครรู้ ต้องเดินเข้าไปดูใกล้ๆ -Such programmers save a little bit on variable declaration but lose ten times more on debugging. +โปรแกรมเมอร์พวกนี้อาจจะประหยัดการประกาศตัวแปรไปได้นิดหน่อย แต่กลับเสียเวลาดีบั๊กไปมากกว่าสิบเท่า -An extra variable is good, not evil. +การมีตัวแปรเพิ่มถือว่าดี ไม่ใช่เรื่องไม่ดี -Modern JavaScript minifiers and browsers optimize code well enough, so it won't create performance issues. Using different variables for different values can even help the engine optimize your code. +JavaScript minifier และเบราว์เซอร์สมัยใหม่ สามารถปรับแต่งโค้ดได้ดีพอที่จะไม่ก่อให้เกิดปัญหาด้านประสิทธิภาพ และการใช้ตัวแปรต่างกันเพื่อเก็บค่าที่ต่างกัน ยังช่วยให้เอนจินสามารถปรับแต่งโค้ดให้ดีขึ้นได้อีกด้วย ``` -## Summary +## สรุป -We can declare variables to store data by using the `var`, `let`, or `const` keywords. +เราสามารถประกาศตัวแปรเพื่อเก็บข้อมูลโดยใช้คีย์เวิร์ด `var`, `let` หรือ `const` -- `let` -- is a modern variable declaration. -- `var` -- is an old-school variable declaration. Normally we don't use it at all, but we'll cover subtle differences from `let` in the chapter , just in case you need them. -- `const` -- is like `let`, but the value of the variable can't be changed. +- `let` -- เป็นรูปแบบการประกาศตัวแปรแบบสมัยใหม่ +- `var` -- เป็นการประกาศตัวแปรแบบเก่า ปกติเราไม่ค่อยใช้แล้ว แต่เราจะกล่าวถึงความแตกต่างเล็กๆ น้อยๆ จาก `let` ในบทเรียน ในกรณีที่คุณจำเป็นต้องใช้มัน +- `const` -- คล้ายกับ `let` แต่ค่าของตัวแปรจะไม่สามารถเปลี่ยนแปลงได้ -Variables should be named in a way that allows us to easily understand what's inside them. +ตัวแปรควรถูกตั้งชื่อในลักษณะที่ทำให้เราสามารถเข้าใจได้โดยง่าย ว่ามีข้อมูลอะไรถูกเก็บอยู่ภายใน diff --git a/1-js/02-first-steps/05-types/1-string-quotes/solution.md b/1-js/02-first-steps/05-types/1-string-quotes/solution.md index 68a13c15b..2c91e5885 100644 --- a/1-js/02-first-steps/05-types/1-string-quotes/solution.md +++ b/1-js/02-first-steps/05-types/1-string-quotes/solution.md @@ -1,5 +1,5 @@ -Backticks embed the expression inside `${...}` into the string. +Backtick สามารถใส่นิพจน์ (expression) ใดๆก็ได้ลงไปใน `${...}` ```js run let name = "Ilya"; diff --git a/1-js/02-first-steps/05-types/1-string-quotes/task.md b/1-js/02-first-steps/05-types/1-string-quotes/task.md index 14ea6b4d6..179502b5d 100644 --- a/1-js/02-first-steps/05-types/1-string-quotes/task.md +++ b/1-js/02-first-steps/05-types/1-string-quotes/task.md @@ -4,7 +4,7 @@ importance: 5 # String quotes -What is the output of the script? +จงเดาผลลัพธ์จากโค้ดด้านล่างนี้ ```js let name = "Ilya"; @@ -14,4 +14,4 @@ alert( `hello ${1}` ); // ? alert( `hello ${"name"}` ); // ? alert( `hello ${name}` ); // ? -``` \ No newline at end of file +``` diff --git a/1-js/02-first-steps/05-types/article.md b/1-js/02-first-steps/05-types/article.md index 04e8b2450..99e0ae6b0 100644 --- a/1-js/02-first-steps/05-types/article.md +++ b/1-js/02-first-steps/05-types/article.md @@ -1,18 +1,18 @@ -# Data types +# ชนิดข้อมูล -A value in JavaScript is always of a certain type. For example, a string or a number. +ค่าใน JavaScript จะมีชนิดข้อมูลเฉพาะเสมอ เช่น `string` หรือ `number` -There are eight basic data types in JavaScript. Here, we'll cover them in general and in the next chapters we'll talk about each of them in detail. +ใน JavaScript มีชนิดข้อมูลพื้นฐาน 8 ประเภท ในที่นี้เราจะกล่าวถึงภาพรวมของแต่ละประเภท และในบทต่อๆ ไปจะอธิบายแต่ละประเภทอย่างละเอียด -We can put any type in a variable. For example, a variable can at one moment be a string and then store a number: +เราสามารถใส่ค่าชนิดใดก็ได้ลงในตัวแปร ยกตัวอย่างเช่น ตัวแปรหนึ่งอาจเป็น `string` ได้ในขณะหนึ่ง แล้วเก็บ `number` ในอีกขณะหนึ่ง: ```js -// no error +// ไม่มี error let message = "hello"; message = 123456; ``` -Programming languages that allow such things, such as JavaScript, are called "dynamically typed", meaning that there exist data types, but variables are not bound to any of them. +ภาษาโปรแกรมที่อนุญาตให้ทำเช่นนี้ได้ เช่น JavaScript จะเรียกว่า "dynamically typed" ซึ่งหมายความว่ามีชนิดข้อมูลหลากหลาย แต่ตัวแปรไม่จำเป็นต้องถูกผูกไว้กับชนิดข้อมูลใดชนิดหนึ่งตายตัว ## Number @@ -21,32 +21,33 @@ let n = 123; n = 12.345; ``` -The *number* type represents both integer and floating point numbers. +ชนิดข้อมูล *number* ใช้แทนได้ทั้งจำนวนเต็มและจำนวนทศนิยม -There are many operations for numbers, e.g. multiplication `*`, division `/`, addition `+`, subtraction `-`, and so on. +มีตัวดำเนินการหลายอย่างสำหรับจำนวน เช่น การคูณ `*`, การหาร `/`, การบวก `+`, การลบ `-` และอื่นๆ -Besides regular numbers, there are so-called "special numeric values" which also belong to this data type: `Infinity`, `-Infinity` and `NaN`. +นอกเหนือจากตัวเลขทั่วไปแล้ว ยังมีค่าที่เรียกว่า "ค่าตัวเลขพิเศษ" ซึ่งก็จัดอยู่ในชนิดข้อมูลนี้ด้วย ได้แก่ `Infinity`, `-Infinity` และ `NaN` -- `Infinity` represents the mathematical [Infinity](https://en.wikipedia.org/wiki/Infinity) ∞. It is a special value that's greater than any number. +- `Infinity` หมายถึง [อนันต์](https://en.wikipedia.org/wiki/Infinity) ∞ ในเชิงคณิตศาสตร์ เป็นค่าพิเศษที่มากกว่าตัวเลขใดๆ - We can get it as a result of division by zero: + เราอาจได้ค่านี้จากการหารด้วยศูนย์: ```js run alert( 1 / 0 ); // Infinity ``` - Or just reference it directly: + หรืออ้างอิงถึงโดยตรง: ```js run alert( Infinity ); // Infinity ``` -- `NaN` represents a computational error. It is a result of an incorrect or an undefined mathematical operation, for instance: + +- `NaN` หมายถึงความผิดพลาดในการคำนวณ เป็นผลลัพธ์จากการดำเนินการทางคณิตศาสตร์ที่ไม่ถูกต้องหรือไม่ได้กำหนดไว้ เช่น: ```js run - alert( "not a number" / 2 ); // NaN, such division is erroneous + alert( "not a number" / 2 ); // NaN เพราะการหารแบบนี้ผิด ``` - `NaN` is sticky. Any further mathematical operation on `NaN` returns `NaN`: + `NaN` มีคุณสมบัติเหนียว การดำเนินการทางคณิตศาสตร์ใดๆ กับ `NaN` จะให้ผลลัพธ์เป็น `NaN` เสมอ: ```js run alert( NaN + 1 ); // NaN @@ -54,20 +55,25 @@ Besides regular numbers, there are so-called "special numeric values" which also alert( "not a number" / 2 - 1 ); // NaN ``` - So, if there's a `NaN` somewhere in a mathematical expression, it propagates to the whole result (there's only one exception to that: `NaN ** 0` is `1`). + ดังนั้นถ้ามี `NaN` อยู่ในนิพจน์ทางคณิตศาสตร์ตรงไหน มันจะแผ่ขยายไปทั่วผลลัพธ์ทั้งหมด (มีข้อยกเว้นเพียงอย่างเดียวคือ `NaN ** 0` จะเป็น `1`) -```smart header="Mathematical operations are safe" -Doing maths is "safe" in JavaScript. We can do anything: divide by zero, treat non-numeric strings as numbers, etc. +```smart header="การดำเนินการทางคณิตศาสตร์มีความปลอดภัย" +การคำนวณทางคณิตศาสตร์ใน JavaScript นั้น "ปลอดภัย" เราสามารถทำอะไรก็ได้ เช่น หารด้วยศูนย์ หรือดำเนินการกับสตริงที่ไม่ใช่ตัวเลขเหมือนเป็นตัวเลข เป็นต้น -The script will never stop with a fatal error ("die"). At worst, we'll get `NaN` as the result. +สคริปต์จะไม่มีวันหยุดทำงานด้วย fatal error ("ตาย") ในกรณีที่แย่ที่สุด ผลลัพธ์ที่ได้จะเป็น `NaN` ``` -Special numeric values formally belong to the "number" type. Of course they are not numbers in the common sense of this word. +อย่างเป็นทางการแล้วค่าตัวเลขพิเศษเหล่านี้จัดอยู่ในชนิดข้อมูล "number" แต่แน่นอนว่ามันไม่ใช่ตัวเลขในความหมายทั่วไปของคำนี้ -We'll see more about working with numbers in the chapter . +เราจะเรียนรู้เพิ่มเติมเกี่ยวกับการใช้งานตัวเลขในบทเรียน ## BigInt [#bigint-type] +<<<<<<< HEAD +ในภาษา JavaScript ชนิดข้อมูล "number" ไม่สามารถแสดงค่าจำนวนเต็มที่มากกว่า (253-1) (ซึ่งก็คือ `9007199254740991`) หรือน้อยกว่า -(253-1) สำหรับจำนวนลบได้อย่างปลอดภัย + +ถ้าจะให้พูดให้ถูกต้องจริงๆ ชนิดข้อมูล "number" จะเก็บจำนวนเต็มที่ใหญ่กว่านั้นได้ (สูงสุดถึง 1.7976931348623157 * 10308) แต่นอกเหนือจากช่วงจำนวนเต็มที่ปลอดภัยคือ ±(253-1) แล้ว จะมีข้อผิดพลาดในการแสดงตัวเลขที่ละเอียด เพราะไม่สามารถเก็บตัวเลขได้ทุกหลักในพื้นที่จัดเก็บแบบคงที่ขนาด 64 บิต ดังนั้นค่าที่เก็บอาจจะเป็นค่า "โดยประมาณ" +======= In JavaScript, the "number" type cannot safely represent integer values larger than (253-1) (that's `9007199254740991`), or less than -(253-1) for negatives. To be really precise, the "number" type can store larger integers (up to 1.7976931348623157 * 10308), but outside of the safe integer range ±(253-1) there'll be a precision error, because not all digits fit into the fixed 64-bit storage. So an "approximate" value may be stored. @@ -82,144 +88,171 @@ console.log(9007199254740991 + 2); // 9007199254740992 So to say, all odd integers greater than (253-1) can't be stored at all in the "number" type. For most purposes ±(253-1) range is quite enough, but sometimes we need the entire range of really big integers, e.g. for cryptography or microsecond-precision timestamps. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +ยกตัวอย่างเช่น จำนวนสองตัวนี้ (ที่อยู่เหนือช่วงปลอดภัยเล็กน้อย) จะมีค่าเท่ากัน: + +```js +console.log(9007199254740991 + 1); // 9007199254740992 +console.log(9007199254740991 + 2); // 9007199254740992 +``` + +หรือพูดได้ว่า จำนวนเต็มคี่ทุกตัวที่มากกว่า (253-1) จะไม่สามารถเก็บในชนิดข้อมูล "number" ได้เลย -`BigInt` type was recently added to the language to represent integers of arbitrary length. +ในการใช้งานส่วนใหญ่ ช่วง ±(253-1) ก็เพียงพอแล้ว แต่บางครั้งเราอาจต้องการช่วงของจำนวนเต็มที่ใหญ่จริงๆ เช่น สำหรับการเข้ารหัสลับหรือการระบุเวลาแบบละเอียดถึงระดับไมโครวินาที -A `BigInt` value is created by appending `n` to the end of an integer: +ชนิดข้อมูล `BigInt` ได้ถูกเพิ่มเข้ามาในภาษาเมื่อไม่นานมานี้ เพื่อใช้แสดงจำนวนเต็มที่มีความยาวเท่าใดก็ได้ + +สร้างค่า `BigInt` ได้โดยใส่ `n` ต่อท้ายจำนวนเต็ม: ```js -// the "n" at the end means it's a BigInt +// ตัว "n" ท้ายสุดหมายความว่าเป็น BigInt const bigInt = 1234567890123456789012345678901234567890n; ``` -As `BigInt` numbers are rarely needed, we don't cover them here, but devoted them a separate chapter . Read it when you need such big numbers. +เนื่องจากไม่ค่อยได้ใช้ตัวเลข `BigInt` บ่อยนัก เราจึงไม่ขอลงรายละเอียดในที่นี้ แต่จะแยกอธิบายไว้ในบทเรียน อ่านได้เมื่อคุณต้องการใช้จำนวนขนาดใหญ่มากๆ นะ + +<<<<<<< HEAD + +```smart header="ปัญหาความเข้ากันได้" +ปัจจุบัน `BigInt` รองรับใน Firefox/Chrome/Edge/Safari แต่ยังไม่รองรับใน IE +``` + +คุณสามารถดูได้จาก [ตารางความเข้ากันได้ของ BigInt บน *MDN*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) ว่ารองรับในเบราว์เซอร์เวอร์ชันใดบ้าง +======= +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ## String -A string in JavaScript must be surrounded by quotes. +ใน JavaScript string ต้องถูกล้อมรอบด้วยเครื่องหมายคำพูด ```js let str = "Hello"; -let str2 = 'Single quotes are ok too'; -let phrase = `can embed another ${str}`; +let str2 = 'ใช้เครื่องหมายคำพูดเดี่ยวก็ได้'; +let phrase = `สามารถฝัง ${str} ได้ด้วย`; ``` -In JavaScript, there are 3 types of quotes. +ใน JavaScript มีเครื่องหมายคำพูด 3 แบบ -1. Double quotes: `"Hello"`. -2. Single quotes: `'Hello'`. -3. Backticks: `Hello`. +1. เครื่องหมายคำพูดคู่: `"สวัสดี"` +2. เครื่องหมายคำพูดเดี่ยว: `'สวัสดี'` +3. แบ็กติก (Backticks): `สวัสดี` -Double and single quotes are "simple" quotes. There's practically no difference between them in JavaScript. +เครื่องหมายคำพูดคู่และเดี่ยวเป็นแบบ "ธรรมดา" ในทางปฏิบัติแล้วไม่มีความแตกต่างระหว่างสองแบบนี้ใน JavaScript -Backticks are "extended functionality" quotes. They allow us to embed variables and expressions into a string by wrapping them in `${…}`, for example: +ส่วนแบ็กติกเป็นเครื่องหมายคำพูดที่มี "ฟังก์ชันเพิ่มเติม" มันช่วยให้เราสามารถแทรกตัวแปรและนิพจน์ลงใน string ได้ โดยครอบด้วย `${…}` เช่น: ```js run -let name = "John"; +let name = "สมชาย"; -// embed a variable -alert( `Hello, *!*${name}*/!*!` ); // Hello, John! +// แทรกตัวแปร +alert( `สวัสดี *!*${name}*/!*!` ); // สวัสดี สมชาย! -// embed an expression -alert( `the result is *!*${1 + 2}*/!*` ); // the result is 3 +// แทรกนิพจน์ +alert( `ผลลัพธ์คือ *!*${1 + 2}*/!*` ); // ผลลัพธ์คือ 3 ``` -The expression inside `${…}` is evaluated and the result becomes a part of the string. We can put anything in there: a variable like `name` or an arithmetical expression like `1 + 2` or something more complex. +นิพจน์ภายใน `${…}` จะถูกประเมินค่า และผลลัพธ์จะกลายเป็นส่วนหนึ่งของ string เราสามารถใส่อะไรก็ได้ลงไปในนั้น ไม่ว่าจะเป็นตัวแปรอย่าง `name` หรือนิพจน์ทางคณิตศาสตร์อย่าง `1 + 2` หรือสิ่งที่ซับซ้อนกว่านั้น + +โปรดจำไว้ว่า การแทรกเช่นนี้ทำได้เฉพาะในแบ็กติกเท่านั้น เครื่องหมายคำพูดรูปแบบอื่นไม่มีความสามารถในการแทรกแบบนี้! -Please note that this can only be done in backticks. Other quotes don't have this embedding functionality! ```js run -alert( "the result is ${1 + 2}" ); // the result is ${1 + 2} (double quotes do nothing) +alert( "ผลลัพธ์คือ ${1 + 2}" ); // ผลลัพธ์คือ ${1 + 2} (เครื่องหมายคำพูดคู่ไม่ได้แทรกอะไร) ``` -We'll cover strings more thoroughly in the chapter . +เราจะพูดถึง string อย่างละเอียดอีกครั้งในบทเรียน -```smart header="There is no *character* type." -In some languages, there is a special "character" type for a single character. For example, in the C language and in Java it is called "char". +```smart header="ไม่มีชนิดข้อมูล *ตัวอักษร*" +ในบางภาษา จะมีชนิดข้อมูลพิเศษ "ตัวอักษร" ไว้แทนอักขระตัวเดียว เช่นในภาษา C และ Java จะเรียกว่า "char" -In JavaScript, there is no such type. There's only one type: `string`. A string may consist of zero characters (be empty), one character or many of them. +แต่ใน JavaScript ไม่มีชนิดข้อมูลเช่นนั้น มีเพียงชนิด `string` เท่านั้น ซึ่ง string อาจเป็นอักขระศูนย์ตัว (ว่างเปล่า), หนึ่งตัว หรือหลายตัวก็ได้ ``` -## Boolean (logical type) +## Boolean (ชนิดข้อมูลตรรกะ) -The boolean type has only two values: `true` and `false`. +ชนิดข้อมูล boolean มีค่าได้เพียงสองค่าเท่านั้น คือ `true` และ `false` -This type is commonly used to store yes/no values: `true` means "yes, correct", and `false` means "no, incorrect". +ชนิดข้อมูลนี้มักใช้สำหรับเก็บค่าแบบ ใช่/ไม่ใช่ โดย `true` หมายถึง "ใช่ ถูกต้อง" ส่วน `false` หมายถึง "ไม่ใช่ ไม่ถูกต้อง" -For instance: +ยกตัวอย่างเช่น: ```js -let nameFieldChecked = true; // yes, name field is checked -let ageFieldChecked = false; // no, age field is not checked +let nameFieldChecked = true; // ใช่ ช่องชื่อถูกเลือก +let ageFieldChecked = false; // ไม่ใช่ ช่องอายุไม่ได้ถูกเลือก ``` -Boolean values also come as a result of comparisons: +นอกจากนี้ ค่า boolean ยังเป็นผลลัพธ์ที่ได้จากการเปรียบเทียบด้วย: ```js run let isGreater = 4 > 1; -alert( isGreater ); // true (the comparison result is "yes") +alert( isGreater ); // true (ผลการเปรียบเทียบคือ "ใช่") ``` -We'll cover booleans more deeply in the chapter . +เราจะกล่าวถึง boolean โดยละเอียดอีกครั้งในบทเรียน -## The "null" value +## ค่า "null" -The special `null` value does not belong to any of the types described above. +ค่าพิเศษ `null` ไม่ได้จัดอยู่ในชนิดข้อมูลที่กล่าวมาข้างต้นเลย -It forms a separate type of its own which contains only the `null` value: +มันเป็นชนิดข้อมูลแยกต่างหาก ที่มีเพียงค่า `null` เท่านั้น: ```js let age = null; ``` -In JavaScript, `null` is not a "reference to a non-existing object" or a "null pointer" like in some other languages. +ใน JavaScript `null` ไม่ใช่ "การอ้างอิงถึงออบเจ็กต์ที่ไม่มีอยู่จริง" หรือ "null pointer" เหมือนในบางภาษา -It's just a special value which represents "nothing", "empty" or "value unknown". +แต่เป็นค่าพิเศษ ที่ใช้แทนความหมาย "ไม่มีอะไร", "ว่างเปล่า" หรือ "ไม่ทราบค่า" -The code above states that `age` is unknown. +ในตัวอย่างโค้ดข้างต้น หมายความว่า `age` เป็นค่าที่ไม่ทราบ -## The "undefined" value +## ค่า "undefined" -The special value `undefined` also stands apart. It makes a type of its own, just like `null`. +ค่าพิเศษ `undefined` นั้นมีลักษณะเฉพาะตัว โดยจัดเป็นชนิดข้อมูลแยกออกมาต่างหาก เช่นเดียวกับ `null` -The meaning of `undefined` is "value is not assigned". +ความหมายของ `undefined` คือ "ยังไม่ได้กำหนดค่า" -If a variable is declared, but not assigned, then its value is `undefined`: +หากตัวแปรถูกประกาศแต่ยังไม่ได้กำหนดค่า ค่าของตัวแปรนั้นจะเป็น `undefined`: ```js run let age; -alert(age); // shows "undefined" +alert(age); // แสดงผลเป็น "undefined" ``` -Technically, it is possible to explicitly assign `undefined` to a variable: +ในทางเทคนิค เราสามารถกำหนดค่า `undefined` ให้กับตัวแปรได้อย่างชัดเจน: ```js run let age = 100; -// change the value to undefined +// เปลี่ยนค่าเป็น undefined age = undefined; -alert(age); // "undefined" +alert(age); // แสดงผลเป็น "undefined" ``` -...But we don't recommend doing that. Normally, one uses `null` to assign an "empty" or "unknown" value to a variable, while `undefined` is reserved as a default initial value for unassigned things. +อย่างไรก็ตาม เราไม่แนะนำให้ทำเช่นนั้น โดยทั่วไปแล้ว นิยมใช้ `null` เพื่อกำหนดค่า "ว่างเปล่า" หรือ "ไม่ทราบค่า" ให้กับตัวแปร ส่วน `undefined` จะถูกสงวนไว้ใช้เป็นค่าเริ่มต้นสำหรับสิ่งที่ยังไม่ได้รับการกำหนดค่า -## Objects and Symbols +## Object และ Symbol -The `object` type is special. +ชนิดข้อมูล `object` นั้นมีความพิเศษ -All other types are called "primitive" because their values can contain only a single thing (be it a string or a number or whatever). In contrast, objects are used to store collections of data and more complex entities. +ชนิดข้อมูลอื่นๆ ทั้งหมดเรียกว่า "primitive" เนื่องจากค่าของชนิดข้อมูลเหล่านั้นสามารถเก็บได้เพียงสิ่งเดียว (ไม่ว่าจะเป็น string, number หรืออย่างอื่น) ในทางตรงกันข้าม object ใช้สำหรับเก็บชุดของข้อมูลและสิ่งที่มีโครงสร้างซับซ้อนกว่า -Being that important, objects deserve a special treatment. We'll deal with them later in the chapter , after we learn more about primitives. +ด้วยความสำคัญดังกล่าว object จึงสมควรได้รับการจัดการเป็นพิเศษ เราจะกล่าวถึงรายละเอียดเกี่ยวกับ object ในบท หลังจากที่เราได้เรียนรู้เพิ่มเติมเกี่ยวกับ primitive แล้ว -The `symbol` type is used to create unique identifiers for objects. We have to mention it here for the sake of completeness, but also postpone the details till we know objects. +ชนิดข้อมูล `symbol` ใช้สำหรับสร้างตัวระบุ (identifier) ที่ไม่ซ้ำกันสำหรับ object เราจำเป็นต้องกล่าวถึงมันที่นี่เพื่อให้ครบถ้วน แต่จะเลื่อนรายละเอียดไปจนกว่าเราจะเข้าใจเรื่อง object -## The typeof operator [#type-typeof] +## typeof operator [#type-typeof] +<<<<<<< HEAD +`typeof` operator จะคืนค่าชนิดข้อมูลของ operand มันมีประโยชน์เมื่อเราต้องการประมวลผลค่าที่มีชนิดข้อมูลแตกต่างกัน หรือเพียงแค่ต้องการตรวจสอบแบบรวดเร็ว +======= The `typeof` operator returns the type of the operand. It's useful when we want to process values of different types differently or just want to do a quick check. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -A call to `typeof x` returns a string with the type name: +การเรียกใช้ `typeof x` จะคืนค่าเป็น string ที่ระบุชื่อชนิดข้อมูล: ```js typeof undefined // "undefined" @@ -247,26 +280,38 @@ typeof alert // "function" (3) */!* ``` -The last three lines may need additional explanation: +สามบรรทัดสุดท้ายอาจต้องมีคำอธิบายเพิ่มเติม: -1. `Math` is a built-in object that provides mathematical operations. We will learn it in the chapter . Here, it serves just as an example of an object. -2. The result of `typeof null` is `"object"`. That's an officially recognized error in `typeof`, coming from very early days of JavaScript and kept for compatibility. Definitely, `null` is not an object. It is a special value with a separate type of its own. The behavior of `typeof` is wrong here. -3. The result of `typeof alert` is `"function"`, because `alert` is a function. We'll study functions in the next chapters where we'll also see that there's no special "function" type in JavaScript. Functions belong to the object type. But `typeof` treats them differently, returning `"function"`. That also comes from the early days of JavaScript. Technically, such behavior isn't correct, but can be convenient in practice. +1. `Math` เป็น built-in object ที่มีฟังก์ชันทางคณิตศาสตร์ให้ใช้งาน เราจะเรียนรู้เพิ่มเติมในบท ที่นี่ใช้เพียงเป็นตัวอย่างของ object เท่านั้น +2. ผลลัพธ์ของ `typeof null` คือ `"object"` ซึ่งเป็นข้อผิดพลาดที่ยอมรับอย่างเป็นทางการใน `typeof` โดยมีมาตั้งแต่ยุคแรกเริ่มของ JavaScript และคงไว้เพื่อให้เข้ากันได้กับโค้ดเก่า อันที่จริง `null` ไม่ใช่ object แต่เป็นค่าพิเศษที่มีชนิดข้อมูลเป็นของตัวเอง การทำงานของ `typeof` ในกรณีนี้จึงไม่ถูกต้อง +3. ผลลัพธ์ของ `typeof alert` คือ `"function"` เพราะ `alert` เป็นฟังก์ชัน เราจะศึกษาเกี่ยวกับฟังก์ชันในบทถัดๆ ไป โดยจะเห็นว่าไม่มีชนิดข้อมูล "function" โดยเฉพาะใน JavaScript ฟังก์ชันจัดเป็นส่วนหนึ่งของชนิดข้อมูล object แต่ `typeof` ปฏิบัติต่อฟังก์ชันแตกต่างออกไป โดยคืนค่าเป็น `"function"` ซึ่งก็เป็นพฤติกรรมที่มีมาตั้งแต่ยุคแรกเริ่มของ JavaScript ในทางเทคนิคแล้ว พฤติกรรมดังกล่าวไม่ถูกต้อง แต่ในทางปฏิบัติอาจสะดวกกว่า -```smart header="The `typeof(x)` syntax" -You may also come across another syntax: `typeof(x)`. It's the same as `typeof x`. +```smart header="ไวยากรณ์ `typeof(x)`" +คุณอาจเจอไวยากรณ์รูปแบบอื่นด้วย เช่น `typeof(x)` ซึ่งมีความหมายเหมือนกับ `typeof x` -To put it clear: `typeof` is an operator, not a function. The parentheses here aren't a part of `typeof`. It's the kind of parentheses used for mathematical grouping. +เพื่อให้ชัดเจน: `typeof` เป็น operator ไม่ใช่ฟังก์ชัน วงเล็บที่เห็นไม่ใช่ส่วนหนึ่งของ `typeof` แต่เป็นวงเล็บที่ใช้เพื่อจัดกลุ่มในเชิงคณิตศาสตร์ -Usually, such parentheses contain a mathematical expression, such as `(2 + 2)`, but here they contain only one argument `(x)`. Syntactically, they allow to avoid a space between the `typeof` operator and its argument, and some people like it. +โดยปกติวงเล็บแบบนี้จะใช้ครอบนิพจน์ทางคณิตศาสตร์ เช่น `(2 + 2)` แต่ในที่นี้มีเพียงอาร์กิวเมนต์เดียวคือ `(x)` ในแง่ของไวยากรณ์ มันช่วยให้ไม่ต้องเว้นวรรคระหว่าง operator `typeof` กับอาร์กิวเมนต์ และบางคนชอบใช้แบบนี้ -Some people prefer `typeof(x)`, although the `typeof x` syntax is much more common. +อย่างไรก็ตาม ไวยากรณ์ `typeof x` ยังคงเป็นที่นิยมใช้กันมากกว่า `typeof(x)` แม้ว่าบางคนจะชอบใช้รูปแบบหลังก็ตาม ``` -## Summary - -There are 8 basic data types in JavaScript. - +## สรุป + +ใน JavaScript มีชนิดข้อมูลพื้นฐาน 8 ชนิด ได้แก่ + +<<<<<<< HEAD +- ชนิดข้อมูล primitive 7 ชนิด: + - `number` สำหรับตัวเลขทุกประเภท ทั้งจำนวนเต็มและทศนิยม โดยจำนวนเต็มจะมีขอบเขตอยู่ที่ ±(253-1) + - `bigint` สำหรับจำนวนเต็มที่มีความยาวเท่าใดก็ได้ + - `string` สำหรับข้อความ โดยข้อความอาจมีตัวอักษรตั้งแต่ศูนย์ตัวขึ้นไป และไม่มีชนิดข้อมูลแยกต่างหากสำหรับตัวอักษรเพียงหนึ่งตัว + - `boolean` สำหรับค่า `true` หรือ `false` + - `null` สำหรับค่าที่ไม่ทราบ เป็นชนิดข้อมูลแยกต่างหากที่มีค่าเพียงค่าเดียวคือ `null` + - `undefined` สำหรับค่าที่ยังไม่ได้กำหนด เป็นชนิดข้อมูลแยกต่างหากที่มีค่าเพียงค่าเดียวคือ `undefined` + - `symbol` สำหรับการสร้างตัวระบุที่ไม่ซ้ำกัน +- และชนิดข้อมูลที่ไม่ใช่ primitive 1 ชนิด: + - `object` สำหรับโครงสร้างข้อมูลที่มีความซับซ้อนมากขึ้น +======= - Seven primitive data types: - `number` for numbers of any kind: integer or floating-point, integers are limited by ±(253-1). - `bigint` for integer numbers of arbitrary length. @@ -277,11 +322,12 @@ There are 8 basic data types in JavaScript. - `symbol` for unique identifiers. - And one non-primitive data type: - `object` for more complex data structures. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -The `typeof` operator allows us to see which type is stored in a variable. +`typeof` operator ช่วยให้เราสามารถตรวจสอบชนิดข้อมูลที่ถูกเก็บอยู่ในตัวแปรได้ -- Usually used as `typeof x`, but `typeof(x)` is also possible. -- Returns a string with the name of the type, like `"string"`. -- For `null` returns `"object"` -- this is an error in the language, it's not actually an object. +- โดยทั่วไปใช้ในรูปแบบ `typeof x` แต่ `typeof(x)` ก็สามารถใช้ได้เช่นกัน +- คืนค่าเป็น string ที่ระบุชื่อชนิดข้อมูล เช่น `"string"` +- สำหรับ `null` จะคืนค่าเป็น `"object"` ซึ่งถือเป็นข้อผิดพลาดในภาษา เพราะจริง ๆ แล้ว `null` ไม่ใช่ object -In the next chapters, we'll concentrate on primitive values and once we're familiar with them, we'll move on to objects. +ในบทต่อ ๆ ไป เราจะมุ่งเน้นไปที่ค่า primitive และเมื่อเราคุ้นเคยกับมันแล้ว เราจะเริ่มศึกษาเกี่ยวกับ object ต่อไป \ No newline at end of file diff --git a/1-js/02-first-steps/06-alert-prompt-confirm/article.md b/1-js/02-first-steps/06-alert-prompt-confirm/article.md index ef0f333cb..426e5e506 100644 --- a/1-js/02-first-steps/06-alert-prompt-confirm/article.md +++ b/1-js/02-first-steps/06-alert-prompt-confirm/article.md @@ -1,44 +1,44 @@ -# Interaction: alert, prompt, confirm +# การโต้ตอบ: alert, prompt, confirm -As we'll be using the browser as our demo environment, let's see a couple of functions to interact with the user: `alert`, `prompt` and `confirm`. +เนื่องจากเราจะใช้เบราว์เซอร์เป็นสภาพแวดล้อมในการสาธิต เรามาดูฟังก์ชันสองสามตัวที่ใช้ในการโต้ตอบกับผู้ใช้กัน ได้แก่ `alert`, `prompt` และ `confirm` ## alert -This one we've seen already. It shows a message and waits for the user to press "OK". +เราเคยเห็น `alert` มาแล้ว มันใช้ในการแสดงข้อความและรอให้ผู้ใช้กดปุ่ม "OK" -For example: +ตัวอย่างเช่น: ```js run alert("Hello"); ``` -The mini-window with the message is called a *modal window*. The word "modal" means that the visitor can't interact with the rest of the page, press other buttons, etc, until they have dealt with the window. In this case -- until they press "OK". +หน้าต่างขนาดเล็กที่แสดงข้อความนี้เรียกว่า *modal window* คำว่า "modal" หมายความว่าผู้ใช้จะไม่สามารถโต้ตอบกับส่วนอื่นๆ ของหน้าเว็บ กดปุ่มอื่นๆ หรือทำอย่างอื่นได้ จนกว่าจะจัดการกับหน้าต่างนี้เสร็จ ในกรณีนี้คือจนกว่าจะกดปุ่ม "OK" ## prompt -The function `prompt` accepts two arguments: +ฟังก์ชัน `prompt` รับอาร์กิวเมนต์สองตัว: ```js no-beautify result = prompt(title, [default]); ``` -It shows a modal window with a text message, an input field for the visitor, and the buttons OK/Cancel. +มันจะแสดง modal window ที่มีข้อความ ช่องให้ผู้ใช้กรอกข้อมูล และปุ่ม OK/Cancel `title` -: The text to show the visitor. +: ข้อความที่จะแสดงให้ผู้ใช้เห็น `default` -: An optional second parameter, the initial value for the input field. +: อาร์กิวเมนต์ที่สองซึ่งเป็นตัวเลือก ใช้เป็นค่าเริ่มต้นสำหรับช่องกรอกข้อมูล -```smart header="The square brackets in syntax `[...]`" -The square brackets around `default` in the syntax above denote that the parameter is optional, not required. +```smart header="วงเล็บในไวยากรณ์ `[...]`" +วงเล็บรอบๆ `default` ในไวยากรณ์ด้านบนหมายความว่าพารามิเตอร์นี้เป็นตัวเลือก ไม่จำเป็นต้องใส่ก็ได้ ``` -The visitor can type something in the prompt input field and press OK. Then we get that text in the `result`. Or they can cancel the input by pressing Cancel or hitting the `key:Esc` key, then we get `null` as the `result`. +ผู้ใช้สามารถพิมพ์ข้อความลงในช่อง prompt แล้วกดปุ่ม OK จากนั้นเราจะได้ข้อความนั้นใน `result` หรือผู้ใช้อาจยกเลิกการป้อนข้อมูลได้โดยกดปุ่ม Cancel หรือกดปุ่ม `Esc` ซึ่งในกรณีนี้ `result` จะมีค่าเป็น `null` -The call to `prompt` returns the text from the input field or `null` if the input was canceled. +การเรียกใช้ `prompt` จะคืนค่าเป็นข้อความจากช่องกรอกข้อมูล หรือเป็น `null` หากมีการยกเลิกการป้อนข้อมูล -For instance: +ตัวอย่างเช่น: ```js run let age = prompt('How old are you?', 100); @@ -46,60 +46,60 @@ let age = prompt('How old are you?', 100); alert(`You are ${age} years old!`); // You are 100 years old! ``` -````warn header="In IE: always supply a `default`" -The second parameter is optional, but if we don't supply it, Internet Explorer will insert the text `"undefined"` into the prompt. +```warn header="ใน IE: ควรระบุ `default` เสมอ" +อาร์กิวเมนต์ที่สองเป็นตัวเลือก แต่หากเราไม่ระบุมัน Internet Explorer จะแทรกข้อความ `"undefined"` ลงในช่อง prompt -Run this code in Internet Explorer to see: +ลองรันโค้ดนี้ใน Internet Explorer เพื่อดู: ```js run let test = prompt("Test"); ``` -So, for prompts to look good in IE, we recommend always providing the second argument: +ดังนั้น เพื่อให้ prompt แสดงผลได้ถูกต้องใน IE เราแนะนำให้ระบุอาร์กิวเมนต์ที่สองเสมอ: ```js run -let test = prompt("Test", ''); // <-- for IE +let test = prompt("Test", ''); // <-- สำหรับ IE +``` ``` -```` ## confirm -The syntax: +ไวยากรณ์: ```js result = confirm(question); ``` -The function `confirm` shows a modal window with a `question` and two buttons: OK and Cancel. +ฟังก์ชัน `confirm` จะแสดง modal window ที่มี `question` และปุ่มสองปุ่มคือ OK และ Cancel -The result is `true` if OK is pressed and `false` otherwise. +ผลลัพธ์จะเป็น `true` หากกดปุ่ม OK และเป็น `false` หากกดปุ่มอื่น -For example: +ตัวอย่างเช่น: ```js run let isBoss = confirm("Are you the boss?"); -alert( isBoss ); // true if OK is pressed +alert( isBoss ); // true ถ้ากด OK ``` -## Summary +## สรุป -We covered 3 browser-specific functions to interact with visitors: +เราได้กล่าวถึงฟังก์ชันเฉพาะของเบราว์เซอร์ 3 ตัวที่ใช้ในการโต้ตอบกับผู้ใช้: `alert` -: shows a message. +: แสดงข้อความ `prompt` -: shows a message asking the user to input text. It returns the text or, if Cancel button or `key:Esc` is clicked, `null`. +: แสดงข้อความขอให้ผู้ใช้ป้อนข้อความ คืนค่าเป็นข้อความนั้น หรือคืนค่า `null` หากกดปุ่ม Cancel หรือ `Esc` -`confirm` -: shows a message and waits for the user to press "OK" or "Cancel". It returns `true` for OK and `false` for Cancel/`key:Esc`. +`confirm` +: แสดงข้อความและรอให้ผู้ใช้กดปุ่ม "OK" หรือ "Cancel" คืนค่า `true` สำหรับปุ่ม OK และ `false` สำหรับปุ่ม Cancel หรือ `Esc` -All these methods are modal: they pause script execution and don't allow the visitor to interact with the rest of the page until the window has been dismissed. +เมธอดทั้งหมดนี้เป็น modal: พวกมันจะหยุดการทำงานของสคริปต์และไม่อนุญาตให้ผู้ใช้โต้ตอบกับส่วนที่เหลือของหน้าจนกว่าจะปิดหน้าต่างนั้นไป -There are two limitations shared by all the methods above: +มีข้อจำกัดสองอย่างที่ใช้กับทุกเมธอดข้างต้น: -1. The exact location of the modal window is determined by the browser. Usually, it's in the center. -2. The exact look of the window also depends on the browser. We can't modify it. +1. ตำแหน่งที่แน่นอนของ modal window จะถูกกำหนดโดยเบราว์เซอร์ โดยปกติจะอยู่ตรงกลาง +2. รูปลักษณ์ที่แน่นอนของหน้าต่างก็ขึ้นอยู่กับเบราว์เซอร์เช่นกัน เราไม่สามารถปรับแต่งได้ -That is the price for simplicity. There are other ways to show nicer windows and richer interaction with the visitor, but if "bells and whistles" do not matter much, these methods work just fine. +นั่นคือราคาของความเรียบง่าย มีวิธีอื่นในการแสดงหน้าต่างที่สวยงามและการโต้ตอบกับผู้ใช้ที่ซับซ้อนกว่านี้ แต่หากฟีเจอร์พิเศษไม่ใช่สิ่งสำคัญ เมธอดเหล่านี้ก็ใช้งานได้ดีเช่นกัน \ No newline at end of file diff --git a/1-js/02-first-steps/07-type-conversions/article.md b/1-js/02-first-steps/07-type-conversions/article.md index 329556141..2b691e8cb 100644 --- a/1-js/02-first-steps/07-type-conversions/article.md +++ b/1-js/02-first-steps/07-type-conversions/article.md @@ -1,102 +1,116 @@ -# Type Conversions +# การแปลงชนิดข้อมูล -Most of the time, operators and functions automatically convert the values given to them to the right type. +โดยทั่วไปแล้ว ตัวดำเนินการและฟังก์ชันจะแปลงค่าที่ส่งเข้ามาให้เป็นชนิดข้อมูลที่ถูกต้องโดยอัตโนมัติ -For example, `alert` automatically converts any value to a string to show it. Mathematical operations convert values to numbers. +ยกตัวอย่างเช่น `alert` จะแปลงค่าเป็น string โดยอัตโนมัติเพื่อนำไปแสดงผล ในขณะที่การดำเนินการทางคณิตศาสตร์จะแปลงค่าเป็นตัวเลข -There are also cases when we need to explicitly convert a value to the expected type. +อย่างไรก็ตาม มีบางกรณีที่เราจำเป็นต้องแปลงค่าเป็นชนิดข้อมูลที่ต้องการ +<<<<<<< HEAD +```smart header="ยังไม่กล่าวถึง object" +ในบทนี้เรายังไม่ครอบคลุมถึง object เราจะพูดถึงแค่ค่า primitive เท่านั้น +======= ```smart header="Not talking about objects yet" In this chapter, we won't cover objects. For now, we'll just be talking about primitives. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Later, after we learn about objects, in the chapter we'll see how objects fit in. +หลังจากที่เราได้เรียนรู้เรื่อง object แล้ว ในบท เราจะได้เห็นว่า object เข้ามาเกี่ยวข้องอย่างไร ``` -## String Conversion +## การแปลงเป็น String -String conversion happens when we need the string form of a value. +การแปลงเป็น string จะเกิดขึ้นเมื่อเราต้องการแสดงค่าในรูปแบบ string -For example, `alert(value)` does it to show the value. +ยกตัวอย่างเช่น `alert(value)` จะแปลงค่าเป็น string เพื่อนำไปแสดงผล -We can also call the `String(value)` function to convert a value to a string: +เรายังสามารถเรียกใช้ฟังก์ชัน `String(value)` เพื่อแปลงค่าเป็น string ได้: ```js run let value = true; alert(typeof value); // boolean *!* -value = String(value); // now value is a string "true" +value = String(value); // ตอนนี้ value เป็น string "true" alert(typeof value); // string */!* ``` -String conversion is mostly obvious. A `false` becomes `"false"`, `null` becomes `"null"`, etc. +การแปลงเป็น string โดยทั่วไปมักจะตรงไปตรงมาอยู่แล้ว เช่น `false` กลายเป็น `"false"`, `null` กลายเป็น `"null"` เป็นต้น -## Numeric Conversion +## การแปลงเป็นตัวเลข +<<<<<<< HEAD +การแปลงเป็นตัวเลขที่เกิดขึ้นในฟังก์ชันและนิพจน์ทางคณิตศาสตร์จะดำเนินการโดยอัตโนมัติ +======= Numeric conversion in mathematical functions and expressions happens automatically. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -For example, when division `/` is applied to non-numbers: +ยกตัวอย่างเช่น เมื่อมีการหาร `/` กับสิ่งที่ไม่ใช่ตัวเลข: ```js run -alert( "6" / "2" ); // 3, strings are converted to numbers +alert( "6" / "2" ); // 3, string ถูกแปลงเป็นตัวเลข ``` -We can use the `Number(value)` function to explicitly convert a `value` to a number: +เราสามารถใช้ฟังก์ชัน `Number(value)` เพื่อแปลง `value` เป็นตัวเลขได้: ```js run let str = "123"; alert(typeof str); // string -let num = Number(str); // becomes a number 123 +let num = Number(str); // กลายเป็นตัวเลข 123 alert(typeof num); // number ``` -Explicit conversion is usually required when we read a value from a string-based source like a text form but expect a number to be entered. +โดยทั่วไปแล้วการแปลงเป็นตัวเลขอย่างชัดเจนจะจำเป็นเมื่อเราอ่านค่าจากแหล่งที่เก็บเป็น string เช่น ฟอร์มข้อความ แต่คาดหวังว่าค่าที่กรอกเข้ามาจะเป็นตัวเลข -If the string is not a valid number, the result of such a conversion is `NaN`. For instance: +ถ้า string ไม่ใช่ตัวเลขที่ถูกต้อง ผลลัพธ์จากการแปลงจะได้เป็น `NaN` ตัวอย่างเช่น: ```js run let age = Number("an arbitrary string instead of a number"); -alert(age); // NaN, conversion failed +alert(age); // NaN, การแปลงล้มเหลว ``` -Numeric conversion rules: +กฎการแปลงเป็นตัวเลข: -| Value | Becomes... | +| ค่า | จะกลายเป็น... | |-------|-------------| |`undefined`|`NaN`| |`null`|`0`| +<<<<<<< HEAD +|true และ false | `1` และ `0` | +| `string` | ช่องว่าง (รวมถึงเว้นวรรค, tab `\t`, ขึ้นบรรทัดใหม่ `\n` เป็นต้น) ที่จุดเริ่มต้นและสิ้นสุดจะถูกละเว้น ถ้า string ที่เหลือว่างเปล่า ผลลัพธ์จะเป็น `0` มิฉะนั้นตัวเลขจะถูก "อ่าน" จาก string เมื่อเกิด error จะได้เป็น `NaN` | +======= |true and false | `1` and `0` | | `string` | Whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from the start and end are removed. If the remaining string is empty, the result is `0`. Otherwise, the number is "read" from the string. An error gives `NaN`. | +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Examples: +ตัวอย่าง: ```js run alert( Number(" 123 ") ); // 123 -alert( Number("123z") ); // NaN (error reading a number at "z") +alert( Number("123z") ); // NaN (เกิด error ตอนอ่านตัวเลขที่ "z") alert( Number(true) ); // 1 alert( Number(false) ); // 0 ``` -Please note that `null` and `undefined` behave differently here: `null` becomes zero while `undefined` becomes `NaN`. +โปรดสังเกตว่า `null` และ `undefined` มีพฤติกรรมที่แตกต่างกันในที่นี้: `null` จะกลายเป็นศูนย์ ในขณะที่ `undefined` จะกลายเป็น `NaN` -Most mathematical operators also perform such conversion, we'll see that in the next chapter. +ตัวดำเนินการทางคณิตศาสตร์ส่วนใหญ่ก็จะทำการแปลงค่าในลักษณะนี้เช่นกัน ซึ่งเราจะได้เห็นในบทถัดไป -## Boolean Conversion +## การแปลงเป็น Boolean -Boolean conversion is the simplest one. +การแปลงเป็น boolean เป็นการแปลงที่ง่ายที่สุด -It happens in logical operations (later we'll meet condition tests and other similar things) but can also be performed explicitly with a call to `Boolean(value)`. +มันจะเกิดขึ้นในการดำเนินการเชิงตรรกะ (ต่อไปเราจะได้เจอกับการทดสอบเงื่อนไขและสิ่งที่คล้ายคลึงกัน) แต่ก็สามารถทำได้อย่างชัดเจนด้วยการเรียกใช้ `Boolean(value)` -The conversion rule: +กฎการแปลง: -- Values that are intuitively "empty", like `0`, an empty string, `null`, `undefined`, and `NaN`, become `false`. -- Other values become `true`. +- ค่าที่ "ว่างเปล่า" ตามความเข้าใจทั่วไป เช่น `0`, string เปล่า, `null`, `undefined` และ `NaN` จะกลายเป็น `false` +- ค่าอื่นๆ จะกลายเป็น `true` -For instance: +ตัวอย่างเช่น: ```js run alert( Boolean(1) ); // true @@ -106,45 +120,49 @@ alert( Boolean("hello") ); // true alert( Boolean("") ); // false ``` -````warn header="Please note: the string with zero `\"0\"` is `true`" -Some languages (namely PHP) treat `"0"` as `false`. But in JavaScript, a non-empty string is always `true`. +```warn header="โปรดสังเกต: string ที่มีเลขศูนย์ `\"0\"` จะเป็น `true`" +ในบางภาษา (โดยเฉพาะ PHP) `"0"` จะถูกพิจารณาว่าเป็น `false` แต่ใน JavaScript string ที่ไม่ว่างเปล่าจะเป็น `true` เสมอ ```js run -alert( Boolean("0") ); // true -alert( Boolean(" ") ); // spaces, also true (any non-empty string is true) +alert( Boolean("0") ); // true +alert( Boolean(" ") ); // เว้นวรรค ก็เป็น true (string ที่ไม่ว่างเปล่าทั้งหมดจะเป็น true) +``` ``` -```` -## Summary +## สรุป -The three most widely used type conversions are to string, to number, and to boolean. +การแปลงชนิดข้อมูลที่พบบ่อยที่สุดมี 3 ประเภท ได้แก่ การแปลงเป็น string, การแปลงเป็นตัวเลข และการแปลงเป็น boolean -**`String Conversion`** -- Occurs when we output something. Can be performed with `String(value)`. The conversion to string is usually obvious for primitive values. +**`การแปลงเป็น String`** -- เกิดขึ้นเมื่อเราแสดงผลอะไรบางอย่าง สามารถทำได้ด้วย `String(value)` โดยทั่วไปการแปลงเป็น string มักจะชัดเจนอยู่แล้วสำหรับค่า primitive -**`Numeric Conversion`** -- Occurs in math operations. Can be performed with `Number(value)`. +**`การแปลงเป็นตัวเลข`** -- เกิดขึ้นในการดำเนินการทางคณิตศาสตร์ สามารถทำได้ด้วย `Number(value)` -The conversion follows the rules: +การแปลงจะเป็นไปตามกฎ: -| Value | Becomes... | +| ค่า | จะกลายเป็น... | |-------|-------------| |`undefined`|`NaN`| |`null`|`0`| |true / false | `1 / 0` | +<<<<<<< HEAD +| `string` | string จะถูกอ่าน "ตามที่เป็น" ส่วนช่องว่าง (รวมถึงเว้นวรรค tab `\t` ขึ้นบรรทัดใหม่ `\n` เป็นต้น) ที่ทั้งสองฝั่งจะถูกละเว้น string เปล่าจะกลายเป็น `0` เมื่อเกิด error จะได้เป็น `NaN` | +======= | `string` | The string is read "as is", whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from both sides are ignored. An empty string becomes `0`. An error gives `NaN`. | +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -**`Boolean Conversion`** -- Occurs in logical operations. Can be performed with `Boolean(value)`. +**`การแปลงเป็น Boolean`** -- เกิดขึ้นในการดำเนินการเชิงตรรกะ สามารถทำได้ด้วย `Boolean(value)` -Follows the rules: +ทำตามกฎ: -| Value | Becomes... | +| ค่า | จะกลายเป็น... | |-------|-------------| |`0`, `null`, `undefined`, `NaN`, `""` |`false`| -|any other value| `true` | +|ค่าอื่นๆ| `true` | -Most of these rules are easy to understand and memorize. The notable exceptions where people usually make mistakes are: +กฎส่วนใหญ่เหล่านี้เข้าใจและจดจำได้ง่าย ข้อยกเว้นที่ควรทราบเพราะมักทำให้เกิดความสับสน ได้แก่: -- `undefined` is `NaN` as a number, not `0`. -- `"0"` and space-only strings like `" "` are true as a boolean. +- `undefined` จะเป็น `NaN` ในรูปแบบตัวเลข ไม่ใช่ `0` +- `"0"` และ string ที่มีแต่เว้นวรรคอย่าง `" "` จะเป็น true ในรูปแบบ boolean -Objects aren't covered here. We'll return to them later in the chapter that is devoted exclusively to objects after we learn more basic things about JavaScript. +ในที่นี้ยังไม่ได้ครอบคลุมถึง object เราจะกลับมาพูดถึงเรื่องนี้อีกครั้งในบท ซึ่งอุทิศให้กับ object โดยเฉพาะ หลังจากที่เราได้เรียนรู้เรื่องพื้นฐานของ JavaScript เพิ่มเติมแล้ว \ No newline at end of file diff --git a/1-js/02-first-steps/08-operators/1-increment-order/solution.md b/1-js/02-first-steps/08-operators/1-increment-order/solution.md index 8a44d798e..ea425ce76 100644 --- a/1-js/02-first-steps/08-operators/1-increment-order/solution.md +++ b/1-js/02-first-steps/08-operators/1-increment-order/solution.md @@ -1,5 +1,5 @@ -The answer is: +คำตอบคือ: - `a = 2` - `b = 2` @@ -9,10 +9,10 @@ The answer is: ```js run no-beautify let a = 1, b = 1; -alert( ++a ); // 2, prefix form returns the new value -alert( b++ ); // 1, postfix form returns the old value +alert( ++a ); // 2, prefix form ส่งค่าใหม่กลับ +alert( b++ ); // 1, postfix form ส่งค่าเก่ากลับ -alert( a ); // 2, incremented once -alert( b ); // 2, incremented once +alert( a ); // 2, เพิ่มมา 1 +alert( b ); // 2, เพิ่มมา 1 ``` diff --git a/1-js/02-first-steps/08-operators/1-increment-order/task.md b/1-js/02-first-steps/08-operators/1-increment-order/task.md index 7db092389..d482f395d 100644 --- a/1-js/02-first-steps/08-operators/1-increment-order/task.md +++ b/1-js/02-first-steps/08-operators/1-increment-order/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# The postfix and prefix forms +# postfix และ prefix forms -What are the final values of all variables `a`, `b`, `c` and `d` after the code below? +อะไรคือผลลัพธ์สุดท้ายของตัสแปร `a`, `b`, `c` และ `d` จากโค้ดด้านล่าง ```js let a = 1, b = 1; diff --git a/1-js/02-first-steps/08-operators/2-assignment-result/solution.md b/1-js/02-first-steps/08-operators/2-assignment-result/solution.md index e3113b4cd..1d96247c0 100644 --- a/1-js/02-first-steps/08-operators/2-assignment-result/solution.md +++ b/1-js/02-first-steps/08-operators/2-assignment-result/solution.md @@ -1,5 +1,5 @@ -The answer is: +คำตอบคือ: -- `a = 4` (multiplied by 2) -- `x = 5` (calculated as 1 + 4) +- `a = 4` (คูณด้วย 2) +- `x = 5` (เหมือนกับ 1 + 4) diff --git a/1-js/02-first-steps/08-operators/2-assignment-result/task.md b/1-js/02-first-steps/08-operators/2-assignment-result/task.md index 5345c9485..b8d789ce8 100644 --- a/1-js/02-first-steps/08-operators/2-assignment-result/task.md +++ b/1-js/02-first-steps/08-operators/2-assignment-result/task.md @@ -2,9 +2,9 @@ importance: 3 --- -# Assignment result +# กำหนดค่าแล้วได้อะไร -What are the values of `a` and `x` after the code below? +อะไรคืือค่าของ `a` และ `x` จากโค้ดด้านล่าง? ```js let a = 2; diff --git a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md index 7370b66af..26ee8185c 100644 --- a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md +++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md @@ -16,6 +16,15 @@ undefined + 1 = NaN // (6) " \t \n" - 2 = -2 // (7) ``` +<<<<<<< HEAD +1. การบวกสตริงว่างกับเลขหนึ่ง `"" + 1` จะแปลงเลข `1` ให้เป็นสตริง : `"" + 1 = "1"` และ เราก็มี `"1" + 0` ต่อ ก็จะใช้กฎเดียวกัน +2. การลบ `-` (จะเหมือนกับดำเนินการทางคณิตฯอื่นๆ) จะทำงานกับตัวเลขเท่านั้น ดังนั้นจะมันจึงแปลงสตริงว่างให้เป็นเลข `0` +3. การบวกกับสตริง จะต่อท้ายเลข `5` กับสตริง +4. การลบจะแปลงทุกอย่างเป็นตัวเลขเสมอ ดังนั้น `" -9 "` จึงได้เลข `-9` (จะแปลงโดยที่ไม่สนใจ spaces ที่อยู่รอบเลขลบเก้าเลย) +5. `null` จะกลายเป็นเลข `0` หากถูกแปลงเป็นตัวเลข +6. `undefined` จะเป็นกลายเป็น `NaN` หากถูกแปลงเป็นตัวเลข +ึึ7. space หน้าและหลังจะถูกตัดออก หากแปลงสตริงเป็นตัวเลข หากสตริงมีอักขระพิเศษอย่าง `\t`, `\n` และตามด้วย space ด้านหน้าและหลัง การแปลงเป็นตัวเลขจะตัด space หน้าและหลังออก ส่วน `\t`, `\n` จะกลายเป็นเลข `0` +======= 1. The addition with a string `"" + 1` converts `1` to a string: `"" + 1 = "1"`, and then we have `"1" + 0`, the same rule is applied. 2. The subtraction `-` (like most math operations) only works with numbers, it converts an empty string `""` to `0`. 3. The addition with a string appends the number `5` to the string. @@ -23,3 +32,4 @@ undefined + 1 = NaN // (6) 5. `null` becomes `0` after the numeric conversion. 6. `undefined` becomes `NaN` after the numeric conversion. 7. Space characters are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 diff --git a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md index 068420c7d..e963dfbcc 100644 --- a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md +++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Type conversions +# การแปลงชนิดข้อมูล -What are results of these expressions? +มาเดาผลลัพธ์จาก expression เหล่านี้กัน ```js no-beautify "" + 1 + 0 @@ -23,4 +23,4 @@ undefined + 1 " \t \n" - 2 ``` -Think well, write down and then compare with the answer. +คิดให้ดีๆ เขียนลงในกระดาษแล้วลองเทียบกับเฉลยดูสิ diff --git a/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md index 209a0702c..40fa1d6cb 100644 --- a/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md +++ b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md @@ -1,6 +1,6 @@ -The reason is that prompt returns user input as a string. +เหตุผลคือพรอมต์จะส่งค่าอะไรที่ผู้ใช้กรอกมาเป็นสตริง -So variables have values `"1"` and `"2"` respectively. +ดังนั้น ตัวแปรทั้งสองจึงมีค่า `"1"` และ `"2"` ตามลำดับ ```js run let a = "1"; // prompt("First number?", 1); @@ -8,10 +8,9 @@ let b = "2"; // prompt("Second number?", 2); alert(a + b); // 12 ``` +เราควรที่จะแปลงสตริงให้เป็นตัวเลขเสียก่อนด้วยเติม `+` ไปข้างหน้ส หรือใช้ `Number()` แทนได้ -What we should do is to convert strings to numbers before `+`. For example, using `Number()` or prepending them with `+`. - -For example, right before `prompt`: +ตัวอย่างใส่ก่อน `prompt` ```js run let a = +prompt("First number?", 1); @@ -20,7 +19,7 @@ let b = +prompt("Second number?", 2); alert(a + b); // 3 ``` -Or in the `alert`: +หรือจะเป็นใน `alert`: ```js run let a = prompt("First number?", 1); @@ -29,4 +28,4 @@ let b = prompt("Second number?", 2); alert(+a + +b); // 3 ``` -Using both unary and binary `+` in the latest code. Looks funny, doesn't it? +การใช้ทั้ง unary และ binary `+` ในโค้ดบรรทัดล่างสุด ดูตลกดีไหม? diff --git a/1-js/02-first-steps/08-operators/4-fix-prompt/task.md b/1-js/02-first-steps/08-operators/4-fix-prompt/task.md index b3ea4a3a3..07e851ffa 100644 --- a/1-js/02-first-steps/08-operators/4-fix-prompt/task.md +++ b/1-js/02-first-steps/08-operators/4-fix-prompt/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Fix the addition +# ช่วยแก้ให้บวกถูกที -Here's a code that asks the user for two numbers and shows their sum. +นี่คือโค้ด ที่จะให้ผู้ใช้กรอกตัวเลขสองตัว แล้วจะโชว์ผลลัพธ์ของเลขทั้งสอง -It works incorrectly. The output in the example below is `12` (for default prompt values). +โค้ดชุดนี้ทำงานไม่ถูก ผลลัพธ์ดันเป็น `12` -Why? Fix it. The result should be `3`. +ทำไมล่ะ? ช่วยแก้ที ผลลัพธ์ควรจะเป็น `3` นะ ```js run let a = prompt("First number?", 1); diff --git a/1-js/02-first-steps/08-operators/article.md b/1-js/02-first-steps/08-operators/article.md index d52c37a17..a649e75b8 100644 --- a/1-js/02-first-steps/08-operators/article.md +++ b/1-js/02-first-steps/08-operators/article.md @@ -1,140 +1,157 @@ -# Basic operators, maths +# ตัวดำเนินการพื้นฐานและคณิตศาสตร์ -We know many operators from school. They are things like addition `+`, multiplication `*`, subtraction `-`, and so on. +หลายคนคุ้นเคยกับตัวดำเนินการทางคณิตศาสตร์มาตั้งแต่สมัยเรียนแล้ว ไม่ว่าจะเป็นการบวก `+` การคูณ `*` การลบ `-` และอื่นๆ อีกมากมาย -In this chapter, we’ll start with simple operators, then concentrate on JavaScript-specific aspects, not covered by school arithmetic. +ในบทนี้ เราจะเริ่มต้นด้วยตัวดำเนินการพื้นฐาน จากนั้นจะเจาะลึกไปที่ลักษณะเฉพาะของ JavaScript ซึ่งไม่ได้เรียนกันในวิชาคณิตศาสตร์ทั่วไป -## Terms: "unary", "binary", "operand" +## ศัพท์น่ารู้: "unary", "binary", "operand" -Before we move on, let's grasp some common terminology. +ก่อนจะเริ่มเรื่องต่อไป เรามาทำความเข้าใจศัพท์ที่ใช้กันทั่วไปเสียก่อน -- *An operand* -- is what operators are applied to. For instance, in the multiplication of `5 * 2` there are two operands: the left operand is `5` and the right operand is `2`. Sometimes, people call these "arguments" instead of "operands". -- An operator is *unary* if it has a single operand. For example, the unary negation `-` reverses the sign of a number: +- _ตัวถูกดำเนินการ (operand)_ คือสิ่งที่ถูกนำไปคำนวณด้วยตัวดำเนินการนั่นเอง ยกตัวอย่างเช่น ในการคูณ `5 * 2` จะมีตัวถูกดำเนินการสองตัว ได้แก่ `5` ที่อยู่ทางซ้าย และ `2` ที่อยู่ทางขวา บางครั้งอาจเรียกตัวถูกดำเนินการว่า "อาร์กิวเมนต์ (argument)" แทนก็ได้ - ```js run - let x = 1; +- ตัวดำเนินการจะเป็นแบบ _unary_ หากมีตัวถูกดำเนินการเพียงตัวเดียว อย่างเช่น การกลับเครื่องหมาย `-` ที่จะกลับเครื่องหมายของตัวเลข: - *!* - x = -x; - */!* - alert( x ); // -1, unary negation was applied - ``` -- An operator is *binary* if it has two operands. The same minus exists in binary form as well: +```js run +<<<<<<< HEAD +let x = 1; - ```js run no-beautify - let x = 1, y = 3; - alert( y - x ); // 2, binary minus subtracts values - ``` +*!* +x = -x; +*/!* + +alert( x ); // -1, มีการใช้ unary negation +======= +alert( 5 % 2 ); // 1, the remainder of 5 divided by 2 +alert( 8 % 3 ); // 2, the remainder of 8 divided by 3 +alert( 8 % 4 ); // 0, the remainder of 8 divided by 4 +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 +``` + +- ตัวดำเนินการจะเป็นแบบ _binary_ หากมีตัวถูกดำเนินการสองตัว เครื่องหมายลบก็มีในรูปแบบ binary ด้วยเช่นกัน: - Formally, in the examples above we have two different operators that share the same symbol: the negation operator, a unary operator that reverses the sign, and the subtraction operator, a binary operator that subtracts one number from another. +```js run no-beautify +let x = 1, y = 3; +alert( y - x ); // 2, binary minus ใช้ลบค่าทั้งสองออกจากกัน +``` + +ถ้าพูดอย่างเป็นทางการ ในตัวอย่างด้านบนมีตัวดำเนินการสองตัวที่ใช้สัญลักษณ์เดียวกัน นั่นคือ ตัวดำเนินการ negation ซึ่งเป็น unary ที่กลับเครื่องหมาย และตัวดำเนินการลบ ซึ่งเป็น binary ที่ลบจำนวนหนึ่งออกจากอีกจำนวนหนึ่ง -## Maths +## คณิตศาสตร์ -The following math operations are supported: +JavaScript รองรับการดำเนินการทางคณิตศาสตร์ต่อไปนี้ -- Addition `+`, -- Subtraction `-`, -- Multiplication `*`, -- Division `/`, -- Remainder `%`, -- Exponentiation `**`. +- บวก `+` +- ลบ `-` +- คูณ `*` +- หาร `/` +- หารเอาเศษ `%` +- ยกกำลัง `**` -The first four are straightforward, while `%` and `**` need a few words about them. +สี่ตัวดำเนินการแรกนั้นไม่ต้องอธิบายอะไรมาก ส่วน `%` และ `**` ขออธิบายเพิ่มเติมสักนิด -### Remainder % +### การหารเอาเศษ % -The remainder operator `%`, despite its appearance, is not related to percents. +แม้จะดูคล้ายเปอร์เซ็นต์ แต่ตัวดำเนินการ `%` ไม่ได้เกี่ยวข้องกับเปอร์เซ็นต์เลย -The result of `a % b` is the [remainder](https://en.wikipedia.org/wiki/Remainder) of the integer division of `a` by `b`. +ผลลัพธ์ของ `a % b` คือ [เศษ](https://en.wikipedia.org/wiki/Remainder) ที่ได้จากการหาร `a` ด้วย `b` แบบจำนวนเต็ม -For instance: +ยกตัวอย่างเช่น ```js run -alert( 5 % 2 ); // 1, the remainder of 5 divided by 2 -alert( 8 % 3 ); // 2, the remainder of 8 divided by 3 -alert( 8 % 4 ); // 0, the remainder of 8 divided by 4 +alert( 5 % 2 ); // 1, เศษของ 5 หาร 2 +alert( 8 % 3 ); // 2, เศษของ 8 หาร 3 +alert( 8 % 4 ); // 0, เศษของ 8 หาร 4 ``` -### Exponentiation ** +### การยกกำลัง ** -The exponentiation operator `a ** b` raises `a` to the power of `b`. +ตัวดำเนินการยกกำลัง `a ** b` จะยกค่า `a` ด้วยเลขชี้กำลัง `b` -In school maths, we write that as ab. +ในวิชาคณิตศาสตร์ เราจะเขียนสิ่งนี้เป็น ab -For instance: +ยกตัวอย่างเช่น ```js run alert( 2 ** 2 ); // 2² = 4 alert( 2 ** 3 ); // 2³ = 8 -alert( 2 ** 4 ); // 2⁴ = 16 +alert( 2 ** 4 ); // 2⁴ = 16 ``` +<<<<<<< HEAD +เหมือนในคณิตศาสตร์ ตัวดำเนินการยกกำลังใช้กับจำนวนที่ไม่ใช่จำนวนเต็มได้ด้วย +======= Just like in maths, the exponentiation operator is defined for non-integer numbers as well. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -For example, a square root is an exponentiation by ½: +อย่างเช่น การหารากกำลังสองก็คือการยกกำลังด้วย ½ ```js run -alert( 4 ** (1/2) ); // 2 (power of 1/2 is the same as a square root) -alert( 8 ** (1/3) ); // 2 (power of 1/3 is the same as a cubic root) +alert( 4 ** (1/2) ); // 2 (ยกกำลัง 1/2 เท่ากับหารากกำลังสอง) +alert( 8 ** (1/3) ); // 2 (ยกกำลัง 1/3 เท่ากับหารากกำลังสาม) ``` +## การต่อสตริงด้วย binary + -## String concatenation with binary + +ลองมาดูคุณสมบัติของตัวดำเนินการใน JavaScript ที่นอกเหนือจากคณิตศาสตร์ในห้องเรียนกันหน่อย +<<<<<<< HEAD +ปกติแล้ว ตัวดำเนินการบวก `+` ใช้สำหรับบวกตัวเลข +======= Let's meet the features of JavaScript operators that are beyond school arithmetics. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Usually, the plus operator `+` sums numbers. - -But, if the binary `+` is applied to strings, it merges (concatenates) them: +แต่ถ้าใช้ `+` แบบ binary กับสตริง มันจะเชื่อม (ต่อ) สตริงเข้าด้วยกัน ```js let s = "my" + "string"; alert(s); // mystring ``` -Note that if any of the operands is a string, then the other one is converted to a string too. +ข้อสังเกตคือ ถ้าตัวถูกดำเนินการตัวใดตัวหนึ่งเป็นสตริง ตัวอื่นก็จะถูกแปลงเป็นสตริงเช่นกัน -For example: +ยกตัวอย่างเช่น ```js run alert( '1' + 2 ); // "12" alert( 2 + '1' ); // "21" ``` -See, it doesn't matter whether the first operand is a string or the second one. +จะเห็นว่าไม่สำคัญว่าสตริงจะอยู่ตัวถูกดำเนินการตัวแรกหรือตัวที่สองก็ตาม -Here's a more complex example: +ลองดูตัวอย่างที่ซับซ้อนขึ้นอีกนิด ```js run -alert(2 + 2 + '1' ); // "41" and not "221" +alert(2 + 2 + '1' ); // "41" ไม่ใช่ "221" ``` -Here, operators work one after another. The first `+` sums two numbers, so it returns `4`, then the next `+` adds the string `1` to it, so it's like `4 + '1' = '41'`. +ในที่นี้ ตัวดำเนินการจะทำงานทีละตัว `+` ตัวแรกจะบวกเลขสองจำนวน ได้ผลเป็น `4`, จากนั้น `+` ตัวถัดไปก็นำ `4` ไปต่อกับสตริง `'1'` เหมือนกับการเขียน `4 + '1' = '41'` ```js run -alert('1' + 2 + 2); // "122" and not "14" +alert('1' + 2 + 2); // "122" ไม่ใช่ "14" ``` -Here, the first operand is a string, the compiler treats the other two operands as strings too. The `2` gets concatenated to `'1'`, so it's like `'1' + 2 = "12"` and `"12" + 2 = "122"`. -The binary `+` is the only operator that supports strings in such a way. Other arithmetic operators work only with numbers and always convert their operands to numbers. +ในตัวอย่างนี้ ตัวถูกดำเนินการตัวแรกเป็นสตริง ตัวแปลภาษาจึงมองว่าตัวถูกดำเนินการอีกสองตัวเป็นสตริงด้วย `2` จะถูกเชื่อมต่อท้าย `'1'` เหมือนการเขียน `'1' + 2 = "12"` และ `"12" + 2 = "122"` + +`+` แบบ binary เป็นตัวดำเนินการตัวเดียวที่รองรับการทำงานกับสตริงในลักษณะนี้ ส่วนตัวดำเนินการคณิตศาสตร์อื่นๆ จะทำงานกับตัวเลขเท่านั้น และจะแปลงค่าตัวถูกดำเนินการเป็นตัวเลขเสมอ -Here's the demo for subtraction and division: +ต่อไปนี้คือตัวอย่างของการลบและการหาร ```js run -alert( 6 - '2' ); // 4, converts '2' to a number -alert( '6' / '2' ); // 3, converts both operands to numbers +alert( 6 - '2' ); // 4, แปลง '2' เป็นตัวเลข +alert( '6' / '2' ); // 3, แปลงตัวถูกดำเนินการทั้งสองตัวเป็นตัวเลข ``` -## Numeric conversion, unary + +## การแปลงเป็นตัวเลข, unary + -The plus `+` exists in two forms: the binary form that we used above and the unary form. +เครื่องหมาย `+` มีสองรูปแบบคือ แบบ binary ที่ใช้ข้างบน และแบบ unary -The unary plus or, in other words, the plus operator `+` applied to a single value, doesn't do anything to numbers. But if the operand is not a number, the unary plus converts it into a number. +unary plus หรือพูดอีกอย่างคือ ตัวดำเนินการบวก `+` ที่ใช้กับค่าเดี่ยว จะไม่ส่งผลอะไรกับตัวเลข แต่ถ้าตัวถูกดำเนินการไม่ใช่ตัวเลข unary plus จะแปลงให้เป็นตัวเลข -For example: +ตัวอย่างเช่น ```js run -// No effect on numbers +// ไม่มีผลกับตัวเลข let x = 1; alert( +x ); // 1 @@ -142,62 +159,66 @@ let y = -2; alert( +y ); // -2 *!* -// Converts non-numbers +// แปลงสิ่งที่ไม่ใช่ตัวเลข alert( +true ); // 1 alert( +"" ); // 0 */!* ``` -It actually does the same thing as `Number(...)`, but is shorter. +โดยทำงานเหมือนกับ `Number(...)` เลย แต่เขียนได้สั้นกว่า -The need to convert strings to numbers arises very often. For example, if we are getting values from HTML form fields, they are usually strings. What if we want to sum them? +เรามักจำเป็นต้องแปลงสตริงเป็นตัวเลขอยู่บ่อยๆ เช่น เวลารับค่าจากช่องกรอกข้อมูลใน HTML ค่าเหล่านั้นมักอยู่ในรูปสตริง แล้วถ้าเราต้องการบวกมันเข้าด้วยกันล่ะ? -The binary plus would add them as strings: +binary plus จะเอาสตริงมาต่อกัน ```js run let apples = "2"; let oranges = "3"; -alert( apples + oranges ); // "23", the binary plus concatenates strings +alert( apples + oranges ); // "23", binary plus ต่อสตริงเข้าด้วยกัน ``` -If we want to treat them as numbers, we need to convert and then sum them: +หากต้องการให้เป็นตัวเลข ต้องแปลงค่าก่อนแล้วจึงบวกกัน ```js run let apples = "2"; let oranges = "3"; *!* -// both values converted to numbers before the binary plus +// ค่าทั้งสองถูกแปลงเป็นตัวเลขก่อนใช้ binary plus alert( +apples + +oranges ); // 5 */!* -// the longer variant +// หรือเขียนแบบยาวๆ ก็ได้ // alert( Number(apples) + Number(oranges) ); // 5 ``` -From a mathematician's standpoint, the abundance of pluses may seem strange. But from a programmer's standpoint, there's nothing special: unary pluses are applied first, they convert strings to numbers, and then the binary plus sums them up. +มองในแง่ของนักคณิตศาสตร์ เครื่องหมายบวกที่เยอะแยะอาจดูแปลกๆ แต่สำหรับโปรแกรมเมอร์แล้วไม่มีอะไรพิเศษ unary plus จะถูกใช้กับค่าก่อน เพื่อแปลงสตริงเป็นตัวเลข จากนั้น binary plus จึงเอาตัวเลขมาบวกกัน -Why are unary pluses applied to values before the binary ones? As we're going to see, that's because of their *higher precedence*. +ทำไม unary plus ถึงถูกใช้กับค่าก่อน binary plus? อย่างที่เราจะได้เห็นต่อไป นั่นเป็นเพราะว่ามันมี *ลำดับความสำคัญ (precedence) ที่สูงกว่า* -## Operator precedence +## ลำดับความสำคัญของตัวดำเนินการ -If an expression has more than one operator, the execution order is defined by their *precedence*, or, in other words, the default priority order of operators. +หากนิพจน์มีตัวดำเนินการมากกว่าหนึ่งตัว ลำดับการประมวลผลจะถูกกำหนดโดย *ลำดับความสำคัญ* หรือพูดอีกนัยหนึ่งคือ ลำดับความสำคัญเริ่มต้นของตัวดำเนินการนั่นเอง -From school, we all know that the multiplication in the expression `1 + 2 * 2` should be calculated before the addition. That's exactly the precedence thing. The multiplication is said to have *a higher precedence* than the addition. +พวกเราทุกคนเรียนรู้ตั้งแต่สมัยอยู่ในโรงเรียนแล้วว่าในนิพจน์ `1 + 2 * 2` ต้องคำนวณการคูณก่อนการบวก นั่นแหละคือสิ่งที่เรียกว่าลำดับความสำคัญ การคูณถือว่ามี *ลำดับความสำคัญสูงกว่า* การบวก -Parentheses override any precedence, so if we're not satisfied with the default order, we can use them to change it. For example, write `(1 + 2) * 2`. +วงเล็บสามารถแทนที่ลำดับความสำคัญใดๆ ก็ได้ ดังนั้นหากเราไม่พอใจกับลำดับเริ่มต้น เราก็สามารถใช้วงเล็บเพื่อเปลี่ยนแปลงได้ เช่น เขียนเป็น `(1 + 2) * 2` -There are many operators in JavaScript. Every operator has a corresponding precedence number. The one with the larger number executes first. If the precedence is the same, the execution order is from left to right. +JavaScript มีตัวดำเนินการอยู่มากมาย แต่ละตัวจะมีตัวเลขลำดับความสำคัญของตัวเอง ตัวที่มีค่ามากกว่าจะถูกประมวลผลก่อน หากลำดับความสำคัญเท่ากัน ลำดับการประมวลผลจะเป็นจากซ้ายไปขวา -Here's an extract from the [precedence table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) (you don't need to remember this, but note that unary operators are higher than corresponding binary ones): +ต่อไปนี้คือข้อมูลบางส่วนจาก[ตารางลำดับความสำคัญ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) (คุณไม่จำเป็นต้องจำ แต่ให้สังเกตว่า unary operator จะสูงกว่า binary operator ที่เทียบเท่ากัน): -| Precedence | Name | Sign | +| ลำดับความสำคัญ | ชื่อ | เครื่องหมาย | |------------|------|------| | ... | ... | ... | | 14 | unary plus | `+` | | 14 | unary negation | `-` | +<<<<<<< HEAD +| 13 | exponentiation | `**` | +======= | 13 | exponentiation | `**` | +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 | 12 | multiplication | `*` | | 12 | division | `/` | | 11 | addition | `+` | @@ -206,13 +227,17 @@ Here's an extract from the [precedence table](https://developer.mozilla.org/en-U | 2 | assignment | `=` | | ... | ... | ... | +<<<<<<< HEAD +ดังที่เห็น "unary plus" มีลำดับความสำคัญ `14` ซึ่งสูงกว่า "addition" (binary plus) ที่มีค่า `11` นั่นจึงเป็นเหตุผลว่าทำไมในนิพจน์ `"+apples + +oranges"` unary plus จึงทำงานก่อน addition +======= As we can see, the "unary plus" has a priority of `14` which is higher than the `11` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -## Assignment +## การกำหนดค่า (Assignment) -Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `2`. +เราขอเน้นย้ำว่า assignment `=` ก็ถือเป็นตัวดำเนินการเช่นกัน มันปรากฏอยู่ในตารางลำดับความสำคัญด้วยค่าที่ต่ำมากคือ `2` -That's why, when we assign a variable, like `x = 2 * 2 + 1`, the calculations are done first and then the `=` is evaluated, storing the result in `x`. +นั่นจึงเป็นเหตุผลว่าทำไมเวลาที่เรากำหนดค่าให้กับตัวแปร เช่น `x = 2 * 2 + 1` การคำนวณจะเสร็จสิ้นก่อน แล้วจึงเริ่มประเมิน `=` และเก็บผลลัพธ์ไว้ใน `x` ```js let x = 2 * 2 + 1; @@ -220,15 +245,15 @@ let x = 2 * 2 + 1; alert( x ); // 5 ``` -### Assignment = returns a value +### Assignment = คืนค่ากลับ -The fact of `=` being an operator, not a "magical" language construct has an interesting implication. +ข้อเท็จจริงที่ว่า `=` เป็นตัวดำเนินการ ไม่ใช่ส่วนประกอบ "วิเศษ" ของภาษา มีนัยยะบางอย่างที่น่าสนใจ -All operators in JavaScript return a value. That's obvious for `+` and `-`, but also true for `=`. +ตัวดำเนินการทุกตัวใน JavaScript จะคืนค่ากลับเสมอ ซึ่งชัดเจนสำหรับ `+` และ `-` รวมถึงเป็นความจริงสำหรับ `=` ด้วย -The call `x = value` writes the `value` into `x` *and then returns it*. +การเรียก `x = value` จะเขียน `value` ลงใน `x` *แล้วคืนค่านั้นกลับมา* -Here's a demo that uses an assignment as part of a more complex expression: +นี่คือตัวอย่างที่ใช้ assignment เป็นส่วนหนึ่งของนิพจน์ที่ซับซ้อนกว่า: ```js run let a = 1; @@ -240,17 +265,17 @@ let c = 3 - (a = b + 1); alert( a ); // 3 alert( c ); // 0 -``` +``` -In the example above, the result of expression `(a = b + 1)` is the value which was assigned to `a` (that is `3`). It is then used for further evaluations. +ในตัวอย่างข้างต้น ผลลัพธ์ของนิพจน์ `(a = b + 1)` คือค่าที่ถูก assign ให้ `a` (นั่นก็คือ `3`) ซึ่งถูกนำไปใช้ในการประเมินค่าต่อไป -Funny code, isn't it? We should understand how it works, because sometimes we see it in JavaScript libraries. +โค้ดนี้ดูตลกไปหน่อยนะ เราควรเข้าใจว่ามันทำงานอย่างไร เพราะบางครั้งเราจะเห็นมันในไลบรารี JavaScript -Although, please don't write the code like that. Such tricks definitely don't make code clearer or readable. +อย่างไรก็ตาม โปรดอย่าเขียนโค้ดแบบนั้นเลย เล่ห์เหลี่ยมเช่นนี้ไม่ได้ช่วยให้โค้ดชัดเจนหรืออ่านง่ายขึ้นแน่นอน -### Chaining assignments +### การต่อ assignment แบบลูกโซ่ -Another interesting feature is the ability to chain assignments: +อีกฟีเจอร์ที่น่าสนใจคือความสามารถในการต่อ assignment แบบลูกโซ่: ```js run let a, b, c; @@ -264,90 +289,94 @@ alert( b ); // 4 alert( c ); // 4 ``` -Chained assignments evaluate from right to left. First, the rightmost expression `2 + 2` is evaluated and then assigned to the variables on the left: `c`, `b` and `a`. At the end, all the variables share a single value. +assignment แบบลูกโซ่จะถูกประเมินจากขวาไปซ้าย แรกสุด นิพจน์ `2 + 2` ทางขวาสุดจะถูกประเมิน แล้วจึง assign ให้กับตัวแปรทางซ้าย ได้แก่ `c`, `b` และ `a` ตามลำดับ ในท้ายที่สุด ตัวแปรทุกตัวจะมีค่าเดียวกัน -Once again, for the purposes of readability it's better to split such code into few lines: +อีกครั้ง เพื่อความง่ายต่อการอ่าน เราควรแยกโค้ดแบบนี้ออกเป็นสองสามบรรทัด: ```js c = 2 + 2; b = c; a = c; ``` -That's easier to read, especially when eye-scanning the code fast. -## Modify-in-place +แบบนี้อ่านง่ายกว่า โดยเฉพาะเวลาที่เรากวาดตามองโค้ดอย่างเร็วๆ + +## การปรับค่าในตัวแปรโดยตรง -We often need to apply an operator to a variable and store the new result in that same variable. +เรามักจะต้องนำตัวดำเนินการไปใช้กับตัวแปรและเก็บผลลัพธ์ใหม่ลงในตัวแปรนั้นเอง -For example: +ตัวอย่างเช่น: ```js let n = 2; n = n + 5; -n = n * 2; +n = n * 2; ``` -This notation can be shortened using the operators `+=` and `*=`: +เราสามารถเขียนโค้ดข้างต้นให้สั้นลงได้โดยใช้ตัวดำเนินการ `+=` และ `*=`: ```js run let n = 2; -n += 5; // now n = 7 (same as n = n + 5) -n *= 2; // now n = 14 (same as n = n * 2) +n += 5; // ตอนนี้ n = 7 (เหมือนกับการเขียน n = n + 5) +n *= 2; // ตอนนี้ n = 14 (เหมือนกับการเขียน n = n * 2) -alert( n ); // 14 +alert( n ); // 14 ``` -Short "modify-and-assign" operators exist for all arithmetical and bitwise operators: `/=`, `-=`, etc. +ตัวดำเนินการ "ปรับค่าและกำหนดค่า" แบบสั้นๆ นี้มีให้ใช้งานสำหรับตัวดำเนินการทางคณิตศาสตร์และระดับบิต (Bitwise) ทุกตัว เช่น `/=`, `-=` เป็นต้น -Such operators have the same precedence as a normal assignment, so they run after most other calculations: +ตัวดำเนินการเหล่านี้จะมีลำดับความสำคัญเท่ากับการกำหนดค่าปกติ ดังนั้นพวกมันจะทำงานหลังจากการคำนวณส่วนอื่นๆ เสร็จสิ้นแล้ว: ```js run let n = 2; +<<<<<<< HEAD +n *= 3 + 5; // คำนวณทางด้านขวาก่อน เหมือนกับการเขียน n *= 8 +======= n *= 3 + 5; // right part evaluated first, same as n *= 8 +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 alert( n ); // 16 ``` -## Increment/decrement +## การเพิ่ม/ลดค่า - +การเพิ่มหรือลดค่าตัวเลขทีละ 1 ถือเป็นหนึ่งในการดำเนินการทางตัวเลขที่ใช้บ่อยที่สุด -Increasing or decreasing a number by one is among the most common numerical operations. +ดังนั้น จึงมีตัวดำเนินการพิเศษสำหรับกรณีนี้: -So, there are special operators for it: - -- **Increment** `++` increases a variable by 1: +- **Increment** `++` ใช้เพิ่มค่าตัวแปรขึ้นทีละ 1: ```js run no-beautify let counter = 2; - counter++; // works the same as counter = counter + 1, but is shorter + counter++; // ทำงานเหมือนกับ counter = counter + 1 แต่เขียนสั้นกว่า alert( counter ); // 3 ``` -- **Decrement** `--` decreases a variable by 1: + +- **Decrement** `--` ใช้ลดค่าตัวแปรลงทีละ 1: ```js run no-beautify let counter = 2; - counter--; // works the same as counter = counter - 1, but is shorter + counter--; // ทำงานเหมือนกับ counter = counter - 1 แต่เขียนสั้นกว่า alert( counter ); // 1 ``` ```warn -Increment/decrement can only be applied to variables. Trying to use it on a value like `5++` will give an error. +Increment/decrement สามารถใช้ได้กับตัวแปรเท่านั้น หากพยายามใช้กับค่าตรงๆ เช่น `5++` จะทำให้เกิด error ``` -The operators `++` and `--` can be placed either before or after a variable. +ตัวดำเนินการ `++` และ `--` สามารถวางไว้ด้านหน้าหรือด้านหลังตัวแปรก็ได้ -- When the operator goes after the variable, it is in "postfix form": `counter++`. -- The "prefix form" is when the operator goes before the variable: `++counter`. +- เมื่อตัวดำเนินการอยู่หลังตัวแปร เรียกว่ารูปแบบ "postfix": `counter++` +- รูปแบบ "prefix" คือเมื่อตัวดำเนินการอยู่หน้าตัวแปร: `++counter` -Both of these statements do the same thing: increase `counter` by `1`. +ทั้งสองแบบทำงานเหมือนกันคือเพิ่มค่า `counter` ขึ้น `1` -Is there any difference? Yes, but we can only see it if we use the returned value of `++/--`. +แล้วมีความแตกต่างกันไหม? มี แต่เราจะเห็นได้ก็ต่อเมื่อนำค่าที่ส่งกลับจาก `++/--` ไปใช้เท่านั้น -Let's clarify. As we know, all operators return a value. Increment/decrement is no exception. The prefix form returns the new value while the postfix form returns the old value (prior to increment/decrement). +เรามาทำความเข้าใจให้ชัดเจนกัน อย่างที่ทราบกันว่าตัวดำเนินการทุกตัวจะส่งค่ากลับ Increment/decrement ก็เช่นกัน รูปแบบ prefix จะส่งค่าใหม่กลับ ส่วนรูปแบบ postfix จะส่งค่าเดิมก่อนการเพิ่ม/ลดค่ากลับ -To see the difference, here's an example: +ลองดูตัวอย่างนี้เพื่อให้เห็นความแตกต่าง: ```js run let counter = 1; @@ -356,79 +385,80 @@ let a = ++counter; // (*) alert(a); // *!*2*/!* ``` -In the line `(*)`, the *prefix* form `++counter` increments `counter` and returns the new value, `2`. So, the `alert` shows `2`. +ในบรรทัด `(*)` รูปแบบ *prefix* `++counter` จะเพิ่มค่า `counter` ก่อนแล้วส่งค่าใหม่ `2` กลับ ดังนั้น `alert` จึงแสดงเลข `2` -Now, let's use the postfix form: +ทีนี้ลองใช้รูปแบบ postfix ดูบ้าง: ```js run let counter = 1; -let a = counter++; // (*) changed ++counter to counter++ +let a = counter++; // (*) เปลี่ยนจาก ++counter เป็น counter++ alert(a); // *!*1*/!* ``` -In the line `(*)`, the *postfix* form `counter++` also increments `counter` but returns the *old* value (prior to increment). So, the `alert` shows `1`. +ในบรรทัด `(*)` รูปแบบ *postfix* `counter++` ก็เพิ่มค่า `counter` เหมือนกัน แต่จะส่งค่า *เดิม* ก่อนการเพิ่มค่ากลับ ดังนั้น `alert` จึงแสดงเลข `1` -To summarize: +สรุปได้ดังนี้: -- If the result of increment/decrement is not used, there is no difference in which form to use: +- ถ้าไม่ได้นำผลลัพธ์ของ increment/decrement ไปใช้ต่อ ไม่ว่าจะใช้รูปแบบไหนก็ไม่ต่างกัน: ```js run let counter = 0; counter++; ++counter; - alert( counter ); // 2, the lines above did the same + alert( counter ); // 2, บรรทัดข้างบนให้ผลเหมือนกัน ``` -- If we'd like to increase a value *and* immediately use the result of the operator, we need the prefix form: - ```js run +- ถ้าต้องการเพิ่มค่า *และ* นำผลลัพธ์ของตัวดำเนินการไปใช้ทันที ต้องใช้รูปแบบ prefix: + + ```js run let counter = 0; alert( ++counter ); // 1 ``` -- If we'd like to increment a value but use its previous value, we need the postfix form: + +- ถ้าต้องการเพิ่มค่า แต่นำค่าก่อนหน้าไปใช้ ต้องใช้รูปแบบ postfix: ```js run let counter = 0; - alert( counter++ ); // 0 + alert( counter++ ); // 0 ``` -````smart header="Increment/decrement among other operators" -The operators `++/--` can be used inside expressions as well. Their precedence is higher than most other arithmetical operations. +```smart header="Increment/decrement ท่ามกลางตัวดำเนินการอื่นๆ" +ตัวดำเนินการ `++/--` สามารถใช้ภายในนิพจน์ได้ด้วย ลำดับความสำคัญของมันสูงกว่าการดำเนินการทางคณิตศาสตร์ส่วนใหญ่ -For instance: +ตัวอย่างเช่น: ```js run let counter = 1; alert( 2 * ++counter ); // 4 ``` -Compare with: +เปรียบเทียบกับ: ```js run let counter = 1; -alert( 2 * counter++ ); // 2, because counter++ returns the "old" value +alert( 2 * counter++ ); // 2, เพราะ counter++ ส่งค่า "เดิม" กลับ ``` -Though technically okay, such notation usually makes code less readable. One line does multiple things -- not good. +ถึงแม้ในแง่เทคนิคจะใช้ได้ แต่การเขียนแบบนี้มักจะทำให้โค้ดอ่านเข้าใจยากขึ้น เพราะทำหลายอย่างในบรรทัดเดียว ซึ่งไม่ค่อยดีนัก -While reading code, a fast "vertical" eye-scan can easily miss something like `counter++` and it won't be obvious that the variable increased. +ระหว่างอ่านโค้ด การสแกนตามแนวดิ่งอย่างรวดเร็วอาจมองข้าม `counter++` ไปได้ง่าย และมันก็ไม่ชัดเจนว่าค่าตัวแปรเพิ่มขึ้น -We advise a style of "one line -- one action": +เราแนะนำให้เขียนแบบ "หนึ่งบรรทัด -- หนึ่งการกระทำ": ```js run let counter = 1; alert( 2 * counter ); counter++; ``` -```` -## Bitwise operators +## ตัวดำเนินการระดับบิต (Bitwise) -Bitwise operators treat arguments as 32-bit integer numbers and work on the level of their binary representation. +ตัวดำเนินการระดับบิต (Bitwise) จะปฏิบัติต่ออาร์กิวเมนต์เป็นจำนวนเต็ม 32 บิต และดำเนินการในระดับการแสดงผลเป็นเลขฐานสอง -These operators are not JavaScript-specific. They are supported in most programming languages. +ตัวดำเนินการเหล่านี้ไม่ได้เฉพาะเจาะจงกับ JavaScript แต่รองรับในภาษาโปรแกรมส่วนใหญ่ -The list of operators: +ตัวดำเนินการมีดังนี้: - AND ( `&` ) - OR ( `|` ) @@ -438,43 +468,47 @@ The list of operators: - RIGHT SHIFT ( `>>` ) - ZERO-FILL RIGHT SHIFT ( `>>>` ) +<<<<<<< HEAD +ตัวดำเนินการเหล่านี้ใช้น้อยมาก เว้นแต่เมื่อเราต้องจัดการกับตัวเลขในระดับ bitwise โดยเฉพาะ เราอาจจะไม่ต้องใช้มันในเร็วๆ นี้ เนื่องจากการพัฒนาเว็บแทบจะไม่ได้ประยุกต์ใช้ แต่ในบางด้านเช่น การเข้ารหัสลับ พวกมันก็ยังมีประโยชน์ คุณสามารถอ่านบท [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) บน MDN เมื่อจำเป็นต้องใช้ +======= These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) chapter on MDN when a need arises. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -## Comma +## ตัวดำเนินการเครื่องหมายจุลภาค (Comma) -The comma operator `,` is one of the rarest and most unusual operators. Sometimes, it's used to write shorter code, so we need to know it in order to understand what's going on. +ตัวดำเนินการเครื่องหมายจุลภาค `,` เป็นหนึ่งในตัวดำเนินการที่พบได้ยากและแปลกประหลาดที่สุด บางครั้งคนใช้มันเพื่อเขียนโค้ดให้สั้นลง เราจึงจำเป็นต้องรู้จักไว้เพื่อให้เข้าใจว่าโค้ดกำลังทำอะไร -The comma operator allows us to evaluate several expressions, dividing them with a comma `,`. Each of them is evaluated but only the result of the last one is returned. +ตัวดำเนินการเครื่องหมายจุลภาคทำให้เราสามารถประเมินนิพจน์ได้หลายตัว โดยคั่นด้วยเครื่องหมายจุลภาค `,` แต่ละนิพจน์จะถูกประเมินผล แต่จะส่งเฉพาะผลลัพธ์ของนิพจน์ตัวสุดท้ายกลับมา -For example: +ตัวอย่างเช่น: ```js run *!* let a = (1 + 2, 3 + 4); */!* -alert( a ); // 7 (the result of 3 + 4) +alert( a ); // 7 (ผลลัพธ์จาก 3 + 4) ``` -Here, the first expression `1 + 2` is evaluated and its result is thrown away. Then, `3 + 4` is evaluated and returned as the result. +ในตัวอย่างนี้ นิพจน์แรก `1 + 2` จะถูกประเมินผลแต่ทิ้งผลลัพธ์ไป จากนั้น `3 + 4` จึงถูกประเมินและส่งค่ากลับมาเป็นผลลัพธ์ -```smart header="Comma has a very low precedence" -Please note that the comma operator has very low precedence, lower than `=`, so parentheses are important in the example above. +```smart header="เครื่องหมายจุลภาคมีลำดับความสำคัญต่ำมาก" +โปรดสังเกตว่าตัวดำเนินการเครื่องหมายจุลภาคมีระดับความสำคัญต่ำมาก ต่ำกว่า `=` ดังนั้นวงเล็บจึงสำคัญในตัวอย่างข้างต้น -Without them: `a = 1 + 2, 3 + 4` evaluates `+` first, summing the numbers into `a = 3, 7`, then the assignment operator `=` assigns `a = 3`, and the rest is ignored. It's like `(a = 1 + 2), 3 + 4`. +หากไม่ใส่วงเล็บ: `a = 1 + 2, 3 + 4` จะประเมิน `+` ก่อน รวมผลเป็น `a = 3, 7` จากนั้นตัวดำเนินการ `=` จะกำหนดค่า `a = 3` และเพิกเฉยต่อส่วนที่เหลือ เสมือนเขียนเป็น `(a = 1 + 2), 3 + 4` ``` -Why do we need an operator that throws away everything except the last expression? +แล้วทำไมเราถึงต้องการตัวดำเนินการที่ทิ้งทุกอย่างยกเว้นนิพจน์ตัวสุดท้าย? -Sometimes, people use it in more complex constructs to put several actions in one line. +บางครั้งคนใช้มันในโครงสร้างที่ซับซ้อนกว่า เพื่อรวมหลายการกระทำไว้ในบรรทัดเดียว -For example: +ตัวอย่างเช่น: ```js -// three operations in one line +// รวมสามการกระทำในบรรทัดเดียว for (*!*a = 1, b = 3, c = a * b*/!*; a < 10; a++) { - ... + ... } ``` -Such tricks are used in many JavaScript frameworks. That's why we're mentioning them. But usually they don't improve code readability so we should think well before using them. +เทคนิคเช่นนี้ถูกใช้ในหลายเฟรมเวิร์กของ JavaScript นั่นเป็นเหตุผลที่เรากล่าวถึงมัน แต่โดยทั่วไปแล้วมันไม่ได้ช่วยให้โค้ดอ่านง่ายขึ้นเลย เราควรคิดให้ดีก่อนนำมาใช้ \ No newline at end of file diff --git a/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md b/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md index 632b1cf4e..90432456d 100644 --- a/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md +++ b/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md @@ -10,12 +10,12 @@ null == "\n0\n" → false null === +"\n0\n" → false ``` -Some of the reasons: +เฉลย: -1. Obviously, true. -2. Dictionary comparison, hence false. `"a"` is smaller than `"p"`. -3. Again, dictionary comparison, first char `"2"` is greater than the first char `"1"`. -4. Values `null` and `undefined` equal each other only. -5. Strict equality is strict. Different types from both sides lead to false. -6. Similar to `(4)`, `null` only equals `undefined`. -7. Strict equality of different types. +1. ได้ true แน่นอน +2. การเปรียบเทียบตามลำดับ Unicode ดังนั้น `"a"` น้อยกว่า `"p"` +3. การเปรียบเทียบตามลำดับ Unicode ดังนั้น `"2"` มากกว่า `"1"`. +4. ค่า `null` และ `undefined` เท่ากันเสมอ เมื่อเทียบด้วย `==` +5. Strict equality นั้นเข้มงวด มันจะตรวจสอบชนิดของข้อมูลด้วย หากชนิดไม่เหมือนกัน ก็ได้จะ false +6. เหมือนกับข้อ `(4)` `null` จะเท่ากับ `undefined` เท่านั้น +7. เหมือนกับข้อ `(5)` diff --git a/1-js/02-first-steps/09-comparison/1-comparison-questions/task.md b/1-js/02-first-steps/09-comparison/1-comparison-questions/task.md index be7f75ddd..818807231 100644 --- a/1-js/02-first-steps/09-comparison/1-comparison-questions/task.md +++ b/1-js/02-first-steps/09-comparison/1-comparison-questions/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Comparisons +# การเปรียบเทียบ -What will be the result for these expressions? +มาเดาผลลัพธ์ที่เกิดจากนิพจน์ด้านล่างกัน ```js no-beautify 5 > 4 diff --git a/1-js/02-first-steps/09-comparison/article.md b/1-js/02-first-steps/09-comparison/article.md index a24af5688..4c0db2e87 100644 --- a/1-js/02-first-steps/09-comparison/article.md +++ b/1-js/02-first-steps/09-comparison/article.md @@ -1,216 +1,224 @@ -# Comparisons +# การเปรียบเทียบ -We know many comparison operators from maths. +เรารู้จักเครื่องหมายเปรียบเทียบ9y;อย่างจากคณิตศาสตร์ -In JavaScript they are written like this: +ใน JavaScript เขียนได้ดังนี้: -- Greater/less than: a > b, a < b. -- Greater/less than or equals: a >= b, a <= b. -- Equals: `a == b`, please note the double equality sign `==` means the equality test, while a single one `a = b` means an assignment. -- Not equals: In maths the notation is , but in JavaScript it's written as a != b. +- มากกว่า/น้อยกว่า: a > b, a < b +- มากกว่าหรือเท่ากับ/น้อยกว่าหรือเท่ากับ: a >= b, a <= b +- เท่ากับ: `a == b` สังเกตว่าต้องใช้เครื่องหมายเท่ากับสองตัว `==` สำหรับการเช็คความเท่ากัน ส่วนเครื่องหมายเดียว `a = b` ใช้สำหรับการกำหนดค่า +- ไม่เท่ากับ: ในเชิงคณิตศาสตร์ใช้สัญลักษณ์ แต่ใน JavaScript เขียนเป็น a != b -In this article we'll learn more about different types of comparisons, how JavaScript makes them, including important peculiarities. +ในบทความนี้ เราจะเรียนรู้เพิ่มเติมเกี่ยวกับการเปรียบเทียบแบบต่างๆ วิธีที่ JavaScript เปรียบเทียบ รวมถึงข้อควรระวังสำคัญ -At the end you'll find a good recipe to avoid "JavaScript quirks"-related issues. +ท้ายบทความมีเคล็ดลับดีๆ ในการหลีกเลี่ยงปัญหาที่มักพบใน JavaScript -## Boolean is the result +## ผลลัพธ์เป็น Boolean -All comparison operators return a boolean value: +ผลการเปรียบเทียบทั้งหมดจะให้ค่า boolean: -- `true` -- means "yes", "correct" or "the truth". -- `false` -- means "no", "wrong" or "not the truth". +- `true` หมายถึง "ใช่" "ถูกต้อง" หรือ "จริง" +- `false` หมายถึง "ไม่" "ไม่ถูกต้อง" หรือ "ไม่จริง" -For example: +ตัวอย่างเช่น: ```js run -alert( 2 > 1 ); // true (correct) -alert( 2 == 1 ); // false (wrong) -alert( 2 != 1 ); // true (correct) +alert( 2 > 1 ); // true (ถูก) +alert( 2 == 1 ); // false (ไม่ถูก) +alert( 2 != 1 ); // true (ถูก) ``` -A comparison result can be assigned to a variable, just like any value: +ผลการเปรียบเทียบสามารถเก็บในตัวแปรได้ เหมือนกับค่าอื่นๆ: ```js run -let result = 5 > 4; // assign the result of the comparison +let result = 5 > 4; // เก็บผลการเปรียบเทียบ alert( result ); // true ``` -## String comparison +## การเปรียบเทียบ string -To see whether a string is greater than another, JavaScript uses the so-called "dictionary" or "lexicographical" order. +ในการเช็คว่า string อันหนึ่งมากกว่าอีกอันหรือไม่ JavaScript ใช้การเรียงลำดับแบบ "พจนานุกรม" หรือ "ตามตัวอักษร" -In other words, strings are compared letter-by-letter. +หรือพูดง่ายๆ คือเปรียบเทียบ string ทีละตัวอักษร -For example: +ตัวอย่างเช่น: ```js run alert( 'Z' > 'A' ); // true alert( 'Glow' > 'Glee' ); // true -alert( 'Bee' > 'Be' ); // true +alert( 'Bee' > 'Be' ); // true ``` -The algorithm to compare two strings is simple: +ขั้นตอนในการเปรียบเทียบ string สองอันมีดังนี้: -1. Compare the first character of both strings. -2. If the first character from the first string is greater (or less) than the other string's, then the first string is greater (or less) than the second. We're done. -3. Otherwise, if both strings' first characters are the same, compare the second characters the same way. -4. Repeat until the end of either string. -5. If both strings end at the same length, then they are equal. Otherwise, the longer string is greater. +1. เปรียบเทียบตัวอักษรตัวแรกของ string ทั้งสองอัน +2. ถ้าตัวอักษรตัวแรกจาก string แรกมากกว่า (หรือน้อยกว่า) string ที่สอง แสดงว่า string แรกมากกว่า (หรือน้อยกว่า) string ที่สอง จบการทำงาน +3. ถ้าตัวอักษรตัวแรกของ string ทั้งสองเหมือนกัน ให้เปรียบเทียบตัวอักษรที่สองแบบเดียวกัน +4. ทำซ้ำไปเรื่อยๆ จนกว่าจะเจอตัวอักษรที่แตกต่างกันหรือจนหมด string +5. ถ้าหมด string พร้อมกันที่ความยาวเท่ากัน แปลว่าเท่ากัน ไม่อย่างนั้น string ที่ยาวกว่าจะมากกว่า -In the first example above, the comparison `'Z' > 'A'` gets to a result at the first step. +ในตัวอย่างแรกข้างบน การเปรียบเทียบ `'Z' > 'A'` ให้ผลลัพธ์ตั้งแต่ขั้นตอนแรก -The second comparison `'Glow'` and `'Glee'` needs more steps as strings are compared character-by-character: +การเปรียบเทียบที่สองระหว่าง `'Glow'` กับ `'Glee'` ต้องใช้หลายขั้นตอนมากกว่า โดยเปรียบเทียบตัวอักษรทีละตัว: -1. `G` is the same as `G`. -2. `l` is the same as `l`. -3. `o` is greater than `e`. Stop here. The first string is greater. +1. `G` เท่ากับ `G` +2. `l` เท่ากับ `l` +3. `o` มากกว่า `e` หยุดตรงนี้ string แรกมากกว่า -```smart header="Not a real dictionary, but Unicode order" -The comparison algorithm given above is roughly equivalent to the one used in dictionaries or phone books, but it's not exactly the same. +```smart header="ไม่ใช่พจนานุกรมจริงๆ แต่เป็นลำดับ Unicode" +ขั้นตอนการเปรียบเทียบข้างต้นคล้ายกับที่ใช้ในพจนานุกรมหรือสมุดโทรศัพท์ แต่ไม่เหมือนกันทีเดียว -For instance, case matters. A capital letter `"A"` is not equal to the lowercase `"a"`. Which one is greater? The lowercase `"a"`. Why? Because the lowercase character has a greater index in the internal encoding table JavaScript uses (Unicode). We'll get back to specific details and consequences of this in the chapter . +เช่น ตัวพิมพ์ใหญ่เล็กมีผล `"A"` ไม่เท่ากับ `"a"` ตัวไหนมากกว่า? `"a"` เพราะมันมีค่าดัชนีที่สูงกว่าในตารางเข้ารหัสภายใน (Unicode) ที่ JavaScript ใช้ เราจะกลับมาดูรายละเอียดและผลที่ตามมาในบท ``` -## Comparison of different types +## การเปรียบเทียบข้อมูลต่างชนิด -When comparing values of different types, JavaScript converts the values to numbers. +เมื่อเปรียบเทียบค่าที่มีชนิดต่างกัน JavaScript จะแปลงค่าเป็นตัวเลขก่อน -For example: +ตัวอย่างเช่น: ```js run -alert( '2' > 1 ); // true, string '2' becomes a number 2 -alert( '01' == 1 ); // true, string '01' becomes a number 1 +alert( '2' > 1 ); // true, string '2' จะถูกแปลงเป็นตัวเลข 2 +alert( '01' == 1 ); // true, string '01' จะถูกแปลงเป็นตัวเลข 1 ``` -For boolean values, `true` becomes `1` and `false` becomes `0`. +สำหรับค่า boolean `true` จะกลายเป็น `1` และ `false` จะกลายเป็น `0` -For example: +ตัวอย่างเช่น: ```js run -alert( true == 1 ); // true +alert( true == 1 ); // true alert( false == 0 ); // true ``` -````smart header="A funny consequence" -It is possible that at the same time: +````smart header="ผลลัพธ์ที่แปลกประหลาด" +มันเป็นไปได้ว่าในเวลาเดียวกัน: -- Two values are equal. -- One of them is `true` as a boolean and the other one is `false` as a boolean. +- สองค่านั้นเท่ากัน +- แต่ค่าหนึ่งเป็น `true` เมื่อแปลงเป็น boolean ส่วนอีกค่าเป็น `false` เมื่อแปลงเป็น boolean -For example: +ตัวอย่างเช่น: ```js run let a = 0; alert( Boolean(a) ); // false -let b = "0"; +let b = "0"; alert( Boolean(b) ); // true alert(a == b); // true! ``` -From JavaScript's standpoint, this result is quite normal. An equality check converts values using the numeric conversion (hence `"0"` becomes `0`), while the explicit `Boolean` conversion uses another set of rules. +จากมุมมองของ JavaScript ผลลัพธ์นี้ถือว่าปกติ การเช็คความเท่ากันจะแปลงค่าโดยใช้การแปลงเป็นตัวเลข (ทำให้ `"0"` เป็น `0`) ในขณะที่การแปลงเป็น `Boolean` โดยตรงใช้ชุดกฎที่แตกต่างกัน ```` -## Strict equality +## ความเท่าเทียมกันอย่างเข้มงวด -A regular equality check `==` has a problem. It cannot differentiate `0` from `false`: +การตรวจสอบความเท่าเทียมกันแบบปกติด้วย `==` มีปัญหาคือไม่สามารถแยกแยะความแตกต่างระหว่าง `0` กับ `false` ได้: ```js run alert( 0 == false ); // true ``` -The same thing happens with an empty string: +เหตุการณ์เดียวกันนี้เกิดขึ้นกับ string ว่างด้วย: -```js run +```js run alert( '' == false ); // true ``` -This happens because operands of different types are converted to numbers by the equality operator `==`. An empty string, just like `false`, becomes a zero. +สิ่งนี้เกิดขึ้นเพราะเมื่อเปรียบเทียบข้อมูลคนละชนิดด้วยเครื่องหมาย `==` JavaScript จะแปลงชนิดข้อมูลเป็นตัวเลขก่อน ทั้ง string ว่างและ `false` จะถูกแปลงเป็นศูนย์ -What to do if we'd like to differentiate `0` from `false`? +แล้วถ้าเราอยากแยกแยะความแตกต่างระหว่าง `0` กับ `false` ล่ะ จะทำอย่างไร? -**A strict equality operator `===` checks the equality without type conversion.** +**เครื่องหมายเท่ากันอย่างเข้มงวด `===` จะเปรียบเทียบความเท่าเทียมกันโดยไม่แปลงชนิดข้อมูล** -In other words, if `a` and `b` are of different types, then `a === b` immediately returns `false` without an attempt to convert them. +อีกนัยหนึ่ง ถ้า `a` และ `b` เป็นคนละชนิดกัน `a === b` จะคืนค่า `false` ทันที โดยไม่พยายามแปลงชนิดข้อมูล -Let's try it: +ลองดูตัวอย่าง: ```js run -alert( 0 === false ); // false, because the types are different +alert( 0 === false ); // false เพราะเป็นคนละชนิดกัน ``` -There is also a "strict non-equality" operator `!==` analogous to `!=`. +นอกจากนี้ยังมีเครื่องหมาย "ไม่เท่ากันอย่างเข้มงวด" `!==` ที่คล้ายกับ `!=` ด้วย -The strict equality operator is a bit longer to write, but makes it obvious what's going on and leaves less room for errors. +การใช้เครื่องหมายเท่ากันแบบเข้มงวดอาจเขียนยาวขึ้นหน่อย แต่จะทำให้เห็นชัดเจนว่าเกิดอะไรขึ้นและลดโอกาสเกิดข้อผิดพลาดได้มากกว่า -## Comparison with null and undefined +## การเปรียบเทียบกับ null และ undefined -There's a non-intuitive behavior when `null` or `undefined` are compared to other values. +เมื่อ `null` หรือ `undefined` ถูกนำมาเปรียบเทียบกับค่าอื่นๆ อาจเกิดพฤติกรรมที่ไม่ตรงกับความคาดหมายเสมอไป -For a strict equality check `===` -: These values are different, because each of them is a different type. +สำหรับการตรวจสอบความเท่ากันอย่างเข้มงวดด้วย `===`: +: ค่าเหล่านี้แตกต่างกัน เพราะแต่ละค่ามีประเภทข้อมูลต่างกัน - ```js run - alert( null === undefined ); // false - ``` +```js run +alert( null === undefined ); // false +``` -For a non-strict check `==` -: There's a special rule. These two are a "sweet couple": they equal each other (in the sense of `==`), but not any other value. +สำหรับการตรวจสอบความเท่ากันแบบไม่เข้มงวดด้วย `==`: +: มีกฎพิเศษ ค่าทั้งสองนี้เป็น "คู่รักในฝัน" คือเท่ากันในแง่ของ `==` แต่ไม่เท่ากับค่าอื่นใด - ```js run - alert( null == undefined ); // true - ``` +```js run +alert( null == undefined ); // true +``` -For maths and other comparisons `< > <= >=` -: `null/undefined` are converted to numbers: `null` becomes `0`, while `undefined` becomes `NaN`. +สำหรับการคำนวณทางคณิตศาสตร์และการเปรียบเทียบอื่นๆ `< > <= >=`: +: `null/undefined` จะถูกแปลงเป็นตัวเลข โดย `null` เป็น `0` และ `undefined` เป็น `NaN` -Now let's see some funny things that happen when we apply these rules. And, what's more important, how to not fall into a trap with them. +เรามาดูเหตุการณ์แปลกๆ ที่เกิดขึ้นเมื่อใช้กฎเหล่านี้ และที่สำคัญกว่านั้น คือเราจะหลีกเลี่ยงกับดักเหล่านี้ได้อย่างไร -### Strange result: null vs 0 +### ผลลัพธ์ประหลาด: null เทียบกับ 0 -Let's compare `null` with a zero: +ลองเปรียบเทียบ `null` กับศูนย์ดู: ```js run alert( null > 0 ); // (1) false alert( null == 0 ); // (2) false -alert( null >= 0 ); // (3) *!*true*/!* +alert( null >= 0 ); // (3) *!*true*/!* ``` -Mathematically, that's strange. The last result states that "`null` is greater than or equal to zero", so in one of the comparisons above it must be `true`, but they are both false. +ทางคณิตศาสตร์แล้วมันแปลกมาก ผลลัพธ์สุดท้ายบอกว่า "`null` มากกว่าหรือเท่ากับศูนย์" ดังนั้นในการเปรียบเทียบข้างต้นต้องมีอย่างน้อยหนึ่งค่าเป็น `true` แต่กลับเป็น false ทั้งคู่ -The reason is that an equality check `==` and comparisons `> < >= <=` work differently. Comparisons convert `null` to a number, treating it as `0`. That's why (3) `null >= 0` is true and (1) `null > 0` is false. +สาเหตุคือ การตรวจสอบความเท่ากันด้วย `==` และการเปรียบเทียบ `> < >= <=` ทำงานต่างกัน การเปรียบเทียบจะแปลง `null` เป็นตัวเลขและถือว่าเป็น `0` นั่นเป็นเหตุผลที่ (3) `null >= 0` เป็น true และ (1) `null > 0` เป็น false -On the other hand, the equality check `==` for `undefined` and `null` is defined such that, without any conversions, they equal each other and don't equal anything else. That's why (2) `null == 0` is false. +ในทางกลับกัน การตรวจสอบความเท่ากันด้วย `==` ระหว่าง `undefined` กับ `null` นั้นถูกกำหนดไว้ว่า หากไม่มีการแปลงประเภท มันจะเท่ากันเองเท่านั้นและไม่เท่ากับค่าอื่นใด นั่นเป็นเหตุผลที่ (2) `null == 0` เป็น false -### An incomparable undefined +### undefined ไม่สามารถเปรียบเทียบได้ -The value `undefined` shouldn't be compared to other values: +เราไม่ควรนำค่า `undefined` ไปเปรียบเทียบกับค่าอื่นๆ: ```js run alert( undefined > 0 ); // false (1) -alert( undefined < 0 ); // false (2) +alert( undefined < 0 ); // false (2) alert( undefined == 0 ); // false (3) ``` -Why does it dislike zero so much? Always false! +ทำไม `undefined` ถึงเกลียดศูนย์ขนาดนั้น จนเป็น false ตลอด! -We get these results because: +เพราะว่า: -- Comparisons `(1)` and `(2)` return `false` because `undefined` gets converted to `NaN` and `NaN` is a special numeric value which returns `false` for all comparisons. -- The equality check `(3)` returns `false` because `undefined` only equals `null`, `undefined`, and no other value. +- การเปรียบเทียบ `(1)` และ `(2)` ให้ค่า `false` เพราะ `undefined` ถูกแปลงเป็น `NaN` ซึ่ง `NaN` เป็นค่าตัวเลขพิเศษที่ให้ผลเป็น `false` เสมอเมื่อเปรียบเทียบ +- การตรวจสอบความเท่ากัน `(3)` ให้ค่า `false` เพราะ `undefined` จะเท่ากับ `null` และ `undefined` เท่านั้น ไม่เท่ากับค่าอื่น -### Avoid problems +### หลีกเลี่ยงปัญหา -Why did we go over these examples? Should we remember these peculiarities all the time? Well, not really. Actually, these tricky things will gradually become familiar over time, but there's a solid way to avoid problems with them: +ทำไมเราถึงยกตัวอย่างเหล่านี้? เราจำเป็นต้องจำความพิเศษเหล่านี้ตลอดเวลาหรือ? ไม่จำเป็นหรอก จริงๆ แล้วสิ่งที่ดูยุ่งยากเหล่านี้จะค่อยๆ คุ้นเคยไปเองตามเวลา แต่มีวิธีที่ดีกว่าในการหลีกเลี่ยงปัญหาพวกนี้: -- Treat any comparison with `undefined/null` except the strict equality `===` with exceptional care. -- Don't use comparisons `>= > < <=` with a variable which may be `null/undefined`, unless you're really sure of what you're doing. If a variable can have these values, check for them separately. +- ระมัดระวังเป็นพิเศษเมื่อเปรียบเทียบกับ `undefined/null` ยกเว้นการตรวจสอบความเท่ากันแบบเข้มงวดด้วย `===` +- อย่าใช้การเปรียบเทียบ `>= > < <=` กับตัวแปรที่อาจเป็น `null/undefined` เว้นแต่คุณจะมั่นใจว่าตัวเองกำลังทำอะไร ถ้าตัวแปรอาจมีค่าเหล่านี้ได้ ให้ตรวจสอบ `null/undefined` แยกต่างหาก -## Summary +## สรุป +<<<<<<< HEAD +- ตัวดำเนินการเปรียบเทียบให้ค่าเป็น boolean +- การเปรียบเทียบ string จะเปรียบเทียบทีละตัวอักษรตามลำดับ "พจนานุกรม" +- เมื่อเปรียบเทียบค่าต่างประเภทกัน ค่าจะถูกแปลงเป็นตัวเลข (ยกเว้นการตรวจสอบความเท่ากันอย่างเข้มงวด) +- ค่า `null` และ `undefined` เท่ากันเฉพาะเมื่อใช้ `==` และไม่เท่ากับค่าอื่นใดทั้งสิ้น +- ระมัดระวังเมื่อใช้การเปรียบเทียบ เช่น `>` หรือ `<` กับตัวแปรที่อาจเป็น `null/undefined` ได้ บางครั้งการตรวจสอบ `null/undefined` แยกต่างหากถือเป็นแนวทางที่ดี +======= - Comparison operators return a boolean value. - Strings are compared letter-by-letter in the "dictionary" order. - When values of different types are compared, they get converted to numbers (with the exclusion of a strict equality check). - The values `null` and `undefined` are equal `==` to themselves and each other, but do not equal any other value. - Be careful when using comparisons like `>` or `<` with variables that can occasionally be `null/undefined`. Checking for `null/undefined` separately is a good idea. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 diff --git a/1-js/02-first-steps/10-ifelse/1-if-zero-string/solution.md b/1-js/02-first-steps/10-ifelse/1-if-zero-string/solution.md index 51f1d4680..a0783893c 100644 --- a/1-js/02-first-steps/10-ifelse/1-if-zero-string/solution.md +++ b/1-js/02-first-steps/10-ifelse/1-if-zero-string/solution.md @@ -1,8 +1,8 @@ -**Yes, it will.** +**ใช่ alert จะโชว์** -Any string except an empty one (and `"0"` is not empty) becomes `true` in the logical context. +สตริงใดๆ ยกเว้นสตริงว่าง (และสตริง "0" ไม่ใช่สตริงเปล่า) จะกลายเป็น "จริง" ในบริบททางตรรกะ -We can run and check: +เราสามรถเรียกใช้เพื่อตรวจสอบได้: ```js run if ("0") { diff --git a/1-js/02-first-steps/10-ifelse/1-if-zero-string/task.md b/1-js/02-first-steps/10-ifelse/1-if-zero-string/task.md index 5f16cda85..a838f144b 100644 --- a/1-js/02-first-steps/10-ifelse/1-if-zero-string/task.md +++ b/1-js/02-first-steps/10-ifelse/1-if-zero-string/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# if (a string with zero) +# if (ศูนย์เป็นสตริง) -Will `alert` be shown? +หลังจากรันโค้ดนี้คิดว่า `alert` จะโชว์ขึ้นมาหรือไม่ ```js if ("0") { diff --git a/1-js/02-first-steps/10-ifelse/2-check-standard/task.md b/1-js/02-first-steps/10-ifelse/2-check-standard/task.md index 4305584fa..1ef523413 100644 --- a/1-js/02-first-steps/10-ifelse/2-check-standard/task.md +++ b/1-js/02-first-steps/10-ifelse/2-check-standard/task.md @@ -2,11 +2,11 @@ importance: 2 --- -# The name of JavaScript +# ชื่ออันแท้จริงของ JavaScript -Using the `if..else` construct, write the code which asks: 'What is the "official" name of JavaScript?' +ใช้รูปโยค `if..else` เขียนโค้ดที่ถามว่า: 'What is the "official" name of JavaScript?' -If the visitor enters "ECMAScript", then output "Right!", otherwise -- output: "You don't know? ECMAScript!" +หากผู้เยี่ยมชมป้อน "ECMAScript" ให้ส่งออกเป็น "Right!" มิฉะนั้น -- ให้ออกเป็น: "You don't know? ECMAScript!" ![](ifelse_task2.svg) diff --git a/1-js/02-first-steps/10-ifelse/3-sign/task.md b/1-js/02-first-steps/10-ifelse/3-sign/task.md index 0c5d0e008..8984bd5b8 100644 --- a/1-js/02-first-steps/10-ifelse/3-sign/task.md +++ b/1-js/02-first-steps/10-ifelse/3-sign/task.md @@ -2,14 +2,14 @@ importance: 2 --- -# Show the sign +# จงแสดงสัญญาณ -Using `if..else`, write the code which gets a number via `prompt` and then shows in `alert`: +ใช้ if..else เขียนโค้ดที่ได้รับตัวเลขผ่าน `prompt` แล้วแสดงใน `alert`: -- `1`, if the value is greater than zero, -- `-1`, if less than zero, -- `0`, if equals zero. +- แสดง `1` ถ้าค่ามากกว่าศูนย์ +- แสดง `-1`, ถ้าค่าน้อยกว่าศูนย์ +- แสดง `0` ถ้าค่าเท่ากับศูนย์ -In this task we assume that the input is always a number. +เราถือว่าอินพุตเป็นตัวเลขเสมอ [demo src="if_sign"] diff --git a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md index 6bdf8453e..de56d4277 100644 --- a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md +++ b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Rewrite 'if' into '?' +# เขียน 'if' ให้เป็น '?' -Rewrite this `if` using the conditional operator `'?'`: +เขียน `if` นี้ใหม่โดยใช้ตัวดำเนินการตามเงื่อนไข `'?'`: ```js let result; diff --git a/1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md b/1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md index 4f7d994a2..240ae0712 100644 --- a/1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md +++ b/1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Rewrite 'if..else' into '?' +# เขียน 'if..else' ให้เป็น '?' -Rewrite `if..else` using multiple ternary operators `'?'`. +เขียน `if..else` นี้ใหม่โดยใช้ตัวดำเนินการตามเงื่อนไข `'?'` -For readability, it's recommended to split the code into multiple lines. +เพื่อให้โค้ดอ่านง่ายขึ้น ขอแนะนำให้แยกโค้ดออกเป็นหลายบรรทัด ```js let message; diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md index 82e8800b9..1daa1531d 100644 --- a/1-js/02-first-steps/10-ifelse/article.md +++ b/1-js/02-first-steps/10-ifelse/article.md @@ -1,239 +1,250 @@ -# Conditional branching: if, '?' +# การกระโดดแบบมีเงื่อนไข: if, '?' -Sometimes, we need to perform different actions based on different conditions. +บ่อยครั้งที่เราต้องทำการต่างๆ ตามเงื่อนไขที่แตกต่างกัน -To do that, we can use the `if` statement and the conditional operator `?`, that's also called a "question mark" operator. +เพื่อทำเช่นนั้น เราสามารถใช้คำสั่ง `if` และตัวดำเนินการแบบมีเงื่อนไข `?` ซึ่งมีอีกชื่อหนึ่งว่า "เครื่องหมายคำถาม" -## The "if" statement +## คำสั่ง "if" -The `if(...)` statement evaluates a condition in parentheses and, if the result is `true`, executes a block of code. +คำสั่ง `if(...)` จะประเมินเงื่อนไขในวงเล็บ ถ้าผลลัพธ์เป็น `true` จะดำเนินการโค้ดในบล็อก -For example: +ตัวอย่างเช่น: ```js run -let year = prompt('In which year was ECMAScript-2015 specification published?', ''); +let year = prompt('มาตรฐาน ECMAScript-2015 เผยแพร่ในปีใด?', ''); *!* -if (year == 2015) alert( 'You are right!' ); +if (year == 2015) alert('คุณตอบถูก!'); */!* ``` -In the example above, the condition is a simple equality check (`year == 2015`), but it can be much more complex. +ในตัวอย่างข้างต้น เงื่อนไขคือการตรวจสอบความเท่ากันแบบง่าย (`year == 2015`) แต่มันอาจซับซ้อนกว่านั้นได้มาก -If we want to execute more than one statement, we have to wrap our code block inside curly braces: +ถ้าเราต้องการรันคำสั่งมากกว่าหนึ่งคำสั่ง เราต้องครอบโค้ดของเราด้วยวงเล็บปีกกา: ```js if (year == 2015) { - alert( "That's correct!" ); - alert( "You're so smart!" ); -} + alert("ถูกต้อง!"); + alert("คุณเก่งมาก!"); +} ``` -We recommend wrapping your code block with curly braces `{}` every time you use an `if` statement, even if there is only one statement to execute. Doing so improves readability. +แนะนำให้ครอบโค้ดของคุณด้วยวงเล็บปีกกา `{}` ทุกครั้งที่ใช้คำสั่ง `if` แม้จะมีเพียงหนึ่งคำสั่งก็ตาม การทำเช่นนี้ช่วยให้อ่านโค้ดง่ายขึ้น -## Boolean conversion +## การแปลงเป็น boolean -The `if (…)` statement evaluates the expression in its parentheses and converts the result to a boolean. +คำสั่ง `if(...)` จะประเมินนิพจน์ในวงเล็บและแปลงผลลัพธ์เป็น boolean -Let's recall the conversion rules from the chapter : +ลองมาทบทวนกฎการแปลงประเภทจากบท กัน: -- A number `0`, an empty string `""`, `null`, `undefined`, and `NaN` all become `false`. Because of that they are called "falsy" values. -- Other values become `true`, so they are called "truthy". +- ตัวเลข `0`, string ว่าง `""`, `null`, `undefined` และ `NaN` จะกลายเป็น `false` ทั้งหมด เรียกค่าเหล่านี้ว่า "falsy" +- ค่าอื่นๆ จะกลายเป็น `true` เรียกว่า "truthy" -So, the code under this condition would never execute: +ดังนั้น โค้ดภายใต้เงื่อนไขนี้จะไม่ถูกรัน: ```js -if (0) { // 0 is falsy +if (0) { // 0 เป็น falsy ... } ``` -...and inside this condition -- it always will: +...แต่ภายในเงื่อนไขนี้ จะรันเสมอ: ```js -if (1) { // 1 is truthy +if (1) { // 1 เป็น truthy ... } ``` -We can also pass a pre-evaluated boolean value to `if`, like this: +เรายังสามารถส่งค่า boolean ที่ประเมินไว้แล้วเข้าไปใน `if` ได้ด้วย แบบนี้: -```js -let cond = (year == 2015); // equality evaluates to true or false +```js +let cond = (year == 2015); // ตรวจสอบความเท่ากัน ได้ค่า true หรือ false if (cond) { - ... + ... } ``` -## The "else" clause +## กรณี "else" +<<<<<<< HEAD +คำสั่ง `if` อาจมีบล็อก `else` เพิ่มเติมได้ ซึ่งจะทำงานเมื่อเงื่อนไขเป็น falsy (เท็จ) +======= The `if` statement may contain an optional `else` block. It executes when the condition is falsy. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -For example: +ตัวอย่างเช่น: ```js run -let year = prompt('In which year was the ECMAScript-2015 specification published?', ''); +let year = prompt('ECMAScript-2015 เผยแพร่ในปีใด?', ''); if (year == 2015) { - alert( 'You guessed it right!' ); + alert('คุณตอบถูกต้อง!'); } else { - alert( 'How can you be so wrong?' ); // any value except 2015 + alert('คุณจำผิดแล้ว'); // สำหรับค่าอื่นๆ ที่ไม่ใช่ 2015 } ``` -## Several conditions: "else if" +## หลายเงื่อนไข: "else if" -Sometimes, we'd like to test several variants of a condition. The `else if` clause lets us do that. +บางครั้งเราอยากทดสอบเงื่อนไขหลายรูปแบบ กรณี `else if` ช่วยให้เราทำแบบนั้นได้ -For example: +ตัวอย่างเช่น: ```js run -let year = prompt('In which year was the ECMAScript-2015 specification published?', ''); +let year = prompt('ECMAScript-2015 เผยแพร่ในปีใด?', ''); if (year < 2015) { - alert( 'Too early...' ); + alert('เร็วไป...'); } else if (year > 2015) { - alert( 'Too late' ); + alert('ช้าไป'); } else { - alert( 'Exactly!' ); + alert('ถูกต้อง!'); } ``` -In the code above, JavaScript first checks `year < 2015`. If that is falsy, it goes to the next condition `year > 2015`. If that is also falsy, it shows the last `alert`. +ในโค้ดข้างต้น JavaScript จะตรวจสอบ `year < 2015` ก่อน ถ้าเป็น falsy จะไปเช็คเงื่อนไขถัดไปคือ `year > 2015` ถ้านั่นก็เป็น falsy ก็จะแสดง `alert` สุดท้าย -There can be more `else if` blocks. The final `else` is optional. +เราสามารถมีบล็อก `else if` ได้หลายบล็อก ส่วน `else` ตัวสุดท้ายเป็นตัวเลือกเสริม ไม่บังคับ -## Conditional operator '?' +## ตัวดำเนินการแบบมีเงื่อนไข '?' -Sometimes, we need to assign a variable depending on a condition. +บางครั้งเราต้องการกำหนดค่าให้ตัวแปรตามเงื่อนไขบางอย่าง -For instance: +ยกตัวอย่างเช่น: ```js run no-beautify let accessAllowed; -let age = prompt('How old are you?', ''); +let age = prompt('อายุเท่าไหร่?', ''); *!* if (age > 18) { accessAllowed = true; } else { - accessAllowed = false; + accessAllowed = false; } */!* alert(accessAllowed); ``` -The so-called "conditional" or "question mark" operator lets us do that in a shorter and simpler way. +ตัวดำเนินการที่เรียกว่า "แบบมีเงื่อนไข" หรือ "เครื่องหมายคำถาม" ช่วยให้เราเขียนโค้ดแบบนี้ได้สั้นและง่ายขึ้น -The operator is represented by a question mark `?`. Sometimes it's called "ternary", because the operator has three operands. It is actually the one and only operator in JavaScript which has that many. +ตัวดำเนินการนี้แทนด้วยเครื่องหมายคำถาม `?` บางครั้งเรียกว่า "ternary" เพราะมี 3 operand ซึ่งเป็นตัวดำเนินการเดียวใน JavaScript ที่มีจำนวน operand มากขนาดนี้ -The syntax is: +รูปแบบไวยากรณ์คือ: ```js let result = condition ? value1 : value2; ``` -The `condition` is evaluated: if it's truthy then `value1` is returned, otherwise -- `value2`. +`condition` จะถูกประเมิน ถ้าเป็น truthy จะคืนค่า `value1` ไม่อย่างนั้นจะคืนค่า `value2` -For example: +ตัวอย่างเช่น: ```js let accessAllowed = (age > 18) ? true : false; ``` -Technically, we can omit the parentheses around `age > 18`. The question mark operator has a low precedence, so it executes after the comparison `>`. +ในทางเทคนิค เราสามารถละวงเล็บรอบ `age > 18` ได้ เพราะตัวดำเนินการ ? มีลำดับความสำคัญต่ำกว่า (precedence) จึงรันหลังเครื่องหมาย `>` -This example will do the same thing as the previous one: +ตัวอย่างนี้จะทำงานเหมือนกับตัวอย่างก่อนหน้า: ```js -// the comparison operator "age > 18" executes first anyway -// (no need to wrap it into parentheses) +// การเปรียบเทียบ "age > 18" รันก่อนอยู่แล้ว +// (ไม่ต้องครอบด้วยวงเล็บก็ได้) let accessAllowed = age > 18 ? true : false; ``` -But parentheses make the code more readable, so we recommend using them. +แต่การใส่วงเล็บช่วยให้โค้ดอ่านง่ายขึ้น จึงแนะนำให้ใส่ไว้ ````smart -In the example above, you can avoid using the question mark operator because the comparison itself returns `true/false`: +ในตัวอย่างข้างต้น จริงๆ แล้วไม่จำเป็นต้องใช้ ? ก็ได้นะ เพราะการเปรียบเทียบเองให้ค่า `true/false` อยู่แล้ว: ```js -// the same +// เหมือนกัน let accessAllowed = age > 18; -``` +``` ```` -## Multiple '?' +## เครื่องหมายคำถามหลายตัว '?' -A sequence of question mark operators `?` can return a value that depends on more than one condition. +การใช้เครื่องหมายคำถาม `?` ต่อเนื่องกันหลายตัว สามารถคืนค่าที่ขึ้นอยู่กับเงื่อนไขมากกว่าหนึ่งอย่างได้ -For instance: +ตัวอย่างเช่น: ```js run -let age = prompt('age?', 18); +let age = prompt('อายุเท่าไหร่?', 18); -let message = (age < 3) ? 'Hi, baby!' : - (age < 18) ? 'Hello!' : - (age < 100) ? 'Greetings!' : - 'What an unusual age!'; +let message = (age < 3) ? 'สวัสดีจ้าหนู!' : + (age < 18) ? 'สวัสดีจ้า!' : + (age < 100) ? 'สวัสดีครับ/ค่ะ!' : + 'อายุแปลกๆ นะ!'; -alert( message ); +alert( message ); ``` -It may be difficult at first to grasp what's going on. But after a closer look, we can see that it's just an ordinary sequence of tests: +อาจดูงงในตอนแรกว่าเกิดอะไรขึ้น แต่ถ้ามองให้ดี จะเห็นว่ามันเป็นเพียงการทดสอบเงื่อนไขทีละข้อตามลำดับ: +<<<<<<< HEAD +1. `?` ตัวแรกตรวจสอบว่า `age < 3` หรือไม่ +2. ถ้าใช่ -- คืนค่า `'สวัสดีจ้าหนู!'` ถ้าไม่ใช่ มันจะไปเช็คเงื่อนไขถัดจากโคลอน ":" คือ `age < 18` +3. ถ้าเงื่อนไขนั้นเป็นจริง -- คืนค่า `'สวัสดีจ้า!'` ถ้าไม่จริง ก็จะไปเช็คเงื่อนไขถัดจากโคลอนถัดไป ":" คือ `age < 100` +4. ถ้านั่นเป็นจริง -- คืนค่า `'สวัสดีครับ/ค่ะ!'` ไม่อย่างนั้นจะไปที่เงื่อนไขสุดท้ายหลังโคลอนตัวสุดท้าย ":" และคืนค่า `'อายุแปลกๆ นะ!'` +======= 1. The first question mark checks whether `age < 3`. 2. If true -- it returns `'Hi, baby!'`. Otherwise, it continues to the expression after the colon ":", checking `age < 18`. 3. If that's true -- it returns `'Hello!'`. Otherwise, it continues to the expression after the next colon ":", checking `age < 100`. 4. If that's true -- it returns `'Greetings!'`. Otherwise, it continues to the expression after the last colon ":", returning `'What an unusual age!'`. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Here's how this looks using `if..else`: +นี่คือการเขียนโค้ดข้างต้นโดยใช้ `if..else`: ```js if (age < 3) { - message = 'Hi, baby!'; + message = 'สวัสดีจ้าหนู!'; } else if (age < 18) { - message = 'Hello!'; + message = 'สวัสดีจ้า!'; } else if (age < 100) { - message = 'Greetings!'; + message = 'สวัสดีครับ/ค่ะ!'; } else { - message = 'What an unusual age!'; + message = 'อายุแปลกๆ นะ!'; } ``` -## Non-traditional use of '?' +## การใช้เครื่องหมายคำถาม '?' แบบไม่เป็นไปตามแบบแผน -Sometimes the question mark `?` is used as a replacement for `if`: +บางครั้งมีการใช้เครื่องหมายคำถาม `?` แทนคำสั่ง `if`: ```js run no-beautify -let company = prompt('Which company created JavaScript?', ''); +let company = prompt('บริษัทใดเป็นผู้สร้าง JavaScript?', ''); *!* (company == 'Netscape') ? - alert('Right!') : alert('Wrong.'); + alert('ถูกต้อง!') : alert('ผิดแล้ว'); */!* ``` -Depending on the condition `company == 'Netscape'`, either the first or the second expression after the `?` gets executed and shows an alert. +ขึ้นอยู่กับเงื่อนไข `company == 'Netscape'` ถ้าเป็นจริงก็จะรันนิพจน์แรกหลัง `?` แต่ถ้าเป็นเท็จจะรันนิพจน์ที่สอง แล้วแสดง alert ออกมา -We don't assign a result to a variable here. Instead, we execute different code depending on the condition. +สังเกตว่าเราไม่ได้กำหนดผลลัพธ์ให้กับตัวแปร แต่เรารันโค้ดที่แตกต่างกันไปตามเงื่อนไข -**It's not recommended to use the question mark operator in this way.** +**ไม่แนะนำให้ใช้เครื่องหมายคำถามในลักษณะนี้นะ** -The notation is shorter than the equivalent `if` statement, which appeals to some programmers. But it is less readable. +การเขียนแบบนี้จะสั้นกว่าใช้คำสั่ง `if` จึงมีนักพัฒนาบางคนชอบ แต่จริงๆ แล้วมันอ่านทำความเข้าใจยากกว่า -Here is the same code using `if` for comparison: +เปรียบเทียบกับการใช้ `if` ในโค้ดเดียวกัน: ```js run no-beautify -let company = prompt('Which company created JavaScript?', ''); +let company = prompt('บริษัทใดเป็นผู้สร้าง JavaScript?', ''); -*!* +*!* if (company == 'Netscape') { - alert('Right!'); + alert('ถูกต้อง!'); } else { - alert('Wrong.'); + alert('ผิดแล้ว'); } */!* ``` -Our eyes scan the code vertically. Code blocks which span several lines are easier to understand than a long, horizontal instruction set. +สายตาเราจะอ่านโค้ดจากบนลงล่าง บล็อกโค้ดที่มีหลายบรรทัดจะเข้าใจง่ายกว่าคำสั่งแบบยาวๆ บรรทัดเดียว -The purpose of the question mark operator `?` is to return one value or another depending on its condition. Please use it for exactly that. Use `if` when you need to execute different branches of code. +จุดประสงค์หลักของเครื่องหมาย `?` คือการคืนค่าอย่างใดอย่างหนึ่งตามเงื่อนไข ควรใช้เพื่อวัตถุประสงค์นั้นโดยเฉพาะ ส่วนถ้าต้องการรันคำสั่งแตกต่างกันตามเงื่อนไข ให้ใช้ `if` จะดีกว่า \ No newline at end of file diff --git a/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md b/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md index 8869d32e6..0c73b435c 100644 --- a/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md +++ b/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md @@ -1,4 +1,4 @@ -The answer is `2`, that's the first truthy value. +คำตอบคือ `2` เพราะว่าเป็นค่า truthy ตัวแรก ```js run alert( null || 2 || undefined ); diff --git a/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md b/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md index a7c9addfc..d48008d44 100644 --- a/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md +++ b/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# What's the result of OR? +# ทายผลลัพธ์ของ OR จากโค้ดต่อไปนี้ -What is the code below going to output? +คิดว่าอะไรจะแสดงที่ออกมาจากฟังก์ชั่น `alert` ```js alert( null || 2 || undefined ); diff --git a/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md b/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md index f85b56366..fa3128b63 100644 --- a/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md +++ b/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md @@ -1,13 +1,13 @@ -The answer: first `1`, then `2`. +คำตอบคือ: `alert` แสดง `1` ก่อน ตามด้วย `2` ```js run alert( alert(1) || 2 || alert(3) ); ``` -The call to `alert` does not return a value. Or, in other words, it returns `undefined`. +การเรียกใช้ฟังก์ชั่น `alert` จะไม่คืนค่าอะไรออกมา หรือก็คือ มันคืน `undefined` มา -1. The first OR `||` evaluates its left operand `alert(1)`. That shows the first message with `1`. -2. The `alert` returns `undefined`, so OR goes on to the second operand searching for a truthy value. -3. The second operand `2` is truthy, so the execution is halted, `2` is returned and then shown by the outer alert. +1. OR `||` ตัวแรกประเมินฟังก์ชั่น `alert(1)` และแสดง `1` ออกมา +2. ฟังก์ชัน `alert` ส่ง `undefined` ซึ่งเป็นค่า falsy กลับดังนั้น OR จะไปประเมินตัวที่สองต่อเพื่อหาค่า truthy +3. ตัวที่สอง `2` เป็นค่า truthy สิ้นสุดการทำงาน เลข `2` ถูกส่งกลับ และแสดงออกมาผ่านฟังก์ชัน `alert` ตัวนอกก -There will be no `3`, because the evaluation does not reach `alert(3)`. +ไม่มีเลข `3` แสดงออกมาเพราะว่าตามการทำงานไปไม่ถึงฟังก์ชั่น `alert(3)` diff --git a/1-js/02-first-steps/11-logical-operators/2-alert-or/task.md b/1-js/02-first-steps/11-logical-operators/2-alert-or/task.md index 3908fa2ec..6dee8a964 100644 --- a/1-js/02-first-steps/11-logical-operators/2-alert-or/task.md +++ b/1-js/02-first-steps/11-logical-operators/2-alert-or/task.md @@ -2,9 +2,9 @@ importance: 3 --- -# What's the result of OR'ed alerts? +# ทายผลลัพธ์ของ OR จากโค้ดต่อไปนี้ -What will the code below output? +อะไรคือจะแสดงออกมาจากฟังก์ชั่น `alert` ```js alert( alert(1) || 2 || alert(3) ); diff --git a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md index 368b59409..f9e11642a 100644 --- a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md +++ b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md @@ -1,4 +1,4 @@ -The answer: `null`, because it's the first falsy value from the list. +คำตอบคือ `null` เพราะว่า มันเป็นค่าที่เป็น falsy แรกที่เจอ ```js run alert(1 && null && 2); diff --git a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md index 043d431e4..c67bdb855 100644 --- a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md +++ b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# What is the result of AND? +# ทายผลลัพธ์ของ AND จากโค้ดต่อไปนี้? -What is this code going to show? +คิดว่าอะไรจะแสดงที่ออกมาจากฟังก์ชั่น `alert` ```js alert( 1 && null && 2 ); diff --git a/1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md b/1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md index b6fb10d72..4053549a1 100644 --- a/1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md +++ b/1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md @@ -1,10 +1,10 @@ -The answer: `1`, and then `undefined`. +คำตอบคือ `1` ตามด้วย `undefined`. ```js run alert( alert(1) && alert(2) ); ``` -The call to `alert` returns `undefined` (it just shows a message, so there's no meaningful return). +เรียกฟังก์ชั่น `alert` จะส่ง `undefined` กลับ (ตัวฟังก์ชั่นมีหน้าที่เพียงแสดงข้อความ ดังนั้นจึงไม่จำเป็นส่งค่าใดๆกลับไป) -Because of that, `&&` evaluates the left operand (outputs `1`), and immediately stops, because `undefined` is a falsy value. And `&&` looks for a falsy value and returns it, so it's done. +เพราะเหตุนี้ `&&` จึงประเมินตัวถูกดำเนินการทางซ้าย (เอาท์พุท `1`) และหยุดทำงานทันที เพราะ `undefined` เป็นค่า falsy และ `&&` จะหาค่า falsy ตัวแรกที่เจอ และส่งค่านั้นกลับไป เป็นอันเสร็จสิ้นการทำงาน diff --git a/1-js/02-first-steps/11-logical-operators/4-alert-and/task.md b/1-js/02-first-steps/11-logical-operators/4-alert-and/task.md index 69f877b95..96de618de 100644 --- a/1-js/02-first-steps/11-logical-operators/4-alert-and/task.md +++ b/1-js/02-first-steps/11-logical-operators/4-alert-and/task.md @@ -2,9 +2,9 @@ importance: 3 --- -# What is the result of AND'ed alerts? +# ทายผลลัพธ์ของ AND จากโค้ดต่อไปนี้? -What will this code show? +คิดว่าอะไรจะแสดงที่ออกมาจากฟังก์ชั่น alert ```js alert( alert(1) && alert(2) ); diff --git a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md index 25e3568f8..00cc59b47 100644 --- a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md +++ b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md @@ -1,16 +1,16 @@ -The answer: `3`. +คำตออบคือ `3` ```js run alert( null || 2 && 3 || 4 ); ``` -The precedence of AND `&&` is higher than `||`, so it executes first. +AND `&&` จะทำงานก่อน `||` เสมอ -The result of `2 && 3 = 3`, so the expression becomes: +ดังนั้นผลลัพธ์ของ `2 && 3 = 3`จากนิพจน์ข้างต้นจึงได้ว่า ``` null || 3 || 4 ``` -Now the result is the first truthy value: `3`. +ตอนนี้ค่า truthy แรกที่เจอก็คือ `3` diff --git a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md index b18bb9c51..5881a1796 100644 --- a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md +++ b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# The result of OR AND OR +# ทายผลลัพธ์ของ OR AND OR จากโค้ดต่อไปนี้? -What will the result be? +คิดว่าอะไรจะแสดงที่ออกมาจากฟังก์ชั่น alert ```js alert( null || 2 && 3 || 4 ); diff --git a/1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md b/1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md index fc9e336c1..17b0ffa71 100644 --- a/1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md +++ b/1-js/02-first-steps/11-logical-operators/6-check-if-in-range/task.md @@ -2,8 +2,8 @@ importance: 3 --- -# Check the range between +# เขียน if ตรวจสอบช่วงตัวเลข -Write an `if` condition to check that `age` is between `14` and `90` inclusively. +เขียนเงื่อนไขแบบ `if` เพื่อตรวจสอบว่า `age` อยู่ระหว่าง `14` ถึง `90` หรือไม่ -"Inclusively" means that `age` can reach the edges `14` or `90`. +โดยรวมอายุ `14` และ `90` ด้วย diff --git a/1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md b/1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md index 9b947d00f..b10acdc4d 100644 --- a/1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md +++ b/1-js/02-first-steps/11-logical-operators/7-check-if-out-range/task.md @@ -2,8 +2,8 @@ importance: 3 --- -# Check the range outside +# เขียน if ตรวจสอบช่วงตัวเลข -Write an `if` condition to check that `age` is NOT between `14` and `90` inclusively. +เขียนเงื่อนไขแบบ `if` เพื่อตรวจสอบว่า `age` อยู่ไม่ระหว่าง `14` และ `90` -Create two variants: the first one using NOT `!`, the second one -- without it. +เขียนสองเงื่อนไข: โดยตัวแรกใช้ NOT `!` และตัวที่สองไม่ใช้ NOT `!` diff --git a/1-js/02-first-steps/11-logical-operators/8-if-question/solution.md b/1-js/02-first-steps/11-logical-operators/8-if-question/solution.md index 210509758..b9aac2b42 100644 --- a/1-js/02-first-steps/11-logical-operators/8-if-question/solution.md +++ b/1-js/02-first-steps/11-logical-operators/8-if-question/solution.md @@ -1,20 +1,20 @@ -The answer: the first and the third will execute. +คำตอบคือ "if" ตัวแรกและตัวที่สามจะทำงาน -Details: +คำอธิบาย: ```js run -// Runs. -// The result of -1 || 0 = -1, truthy +// คำสั่งนี้ทำงาน +// ผลลัพธ์คือ -1 || 0 = -1 เป็นค่า truthy if (-1 || 0) alert( 'first' ); -// Doesn't run -// -1 && 0 = 0, falsy +// คำสั่งนี้ไม่ทำงาน +// -1 && 0 = 0 เป็นค่า falsy if (-1 && 0) alert( 'second' ); -// Executes -// Operator && has a higher precedence than || -// so -1 && 1 executes first, giving us the chain: -// null || -1 && 1 -> null || 1 -> 1 +// คำสั่งนี้ทำงาน +// ตัวดำเนินการ && จะทำงานก่อน || เสมอ +// ดังนั้น -1 && 1 ทำงานเสร็จ ก็จะทำงานส่วนที่เหลือต่อ +// null || -1 && 1 จะเป็น null || 1 จะเป็น 1 if (null || -1 && 1) alert( 'third' ); ``` diff --git a/1-js/02-first-steps/11-logical-operators/8-if-question/task.md b/1-js/02-first-steps/11-logical-operators/8-if-question/task.md index 55987121b..2f31c0c2b 100644 --- a/1-js/02-first-steps/11-logical-operators/8-if-question/task.md +++ b/1-js/02-first-steps/11-logical-operators/8-if-question/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# A question about "if" +# ปัญหาของ "if" -Which of these `alert`s are going to execute? +จากคำสั่ง "if" ทั้งสาม `alert` ตัวไหนจะทำงานบ้าง -What will the results of the expressions be inside `if(...)`? +และผลลัพธ์สุดท้ายภายใน `if(...)` จะเป็นอะไร ```js if (-1 || 0) alert( 'first' ); diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md b/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md index 604606259..128866c27 100644 --- a/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md +++ b/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md @@ -22,4 +22,4 @@ if (userName === 'Admin') { } ``` -Note the vertical indents inside the `if` blocks. They are technically not required, but make the code more readable. +สังเกตการระยะห่างแนวตั้งภายในบล็อก `if` ในทางเทคนิคไม่จำเป็นต้องมีก็ได้ โค้ดก็ทำงานเหมือนเดิม เราเติมช่องว่างเข้าไปเพื่อให้โค้ดอ่านง่ายขึ้น diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/task.md b/1-js/02-first-steps/11-logical-operators/9-check-login/task.md index 290a52642..7e8f7e840 100644 --- a/1-js/02-first-steps/11-logical-operators/9-check-login/task.md +++ b/1-js/02-first-steps/11-logical-operators/9-check-login/task.md @@ -2,24 +2,24 @@ importance: 3 --- -# Check the login +# มาเริ่มสร้างฟอร์มล็อคอินผ่าน prompt -Write the code which asks for a login with `prompt`. +สร้างฟอร์มล็อคอินด้วยฟังก์ชั่น `prompt` -If the visitor enters `"Admin"`, then `prompt` for a password, if the input is an empty line or `key:Esc` -- show "Canceled", if it's another string -- then show "I don't know you". +หากผู้เยี่ยมชมป้อน `"Admin"` ให้ใช้ฟังก์ชั่น `prompt` ถามรหัสผ่าน หากป้อนสตริงว่าง หรือกด `key:Esc` ให้แสดงคำว่า "Canceled" และหากป้อนสตริงอื่นให้แสดงคำว่า "I don't know you" -The password is checked as follows: +กฎการตรวจสอบรหัสผ่านคือดังนี้: -- If it equals "TheMaster", then show "Welcome!", -- Another string -- show "Wrong password", -- For an empty string or cancelled input, show "Canceled" +- หากรหัสผ่านเท่ากับ "TheMaster" ให้แสดงคำว่า "Welcome!", +- หากไม่ใช่ให้แสดงคำว่า "Wrong password", +- หากป้อนสตริงว่าง หรือกด `key:Esc` ให้แสดงคำว่า "Canceled" -The schema: +Schema: ![](ifelse_task.svg) -Please use nested `if` blocks. Mind the overall readability of the code. +โปรดใช้บล็อค `if` ให้คำนึงถึงความอ่านง่ายของโค้ด -Hint: passing an empty input to a prompt returns an empty string `''`. Pressing `key:ESC` during a prompt returns `null`. +คำใบ้: หากไม่ใส่อะไรลงในช่องอินพุทมันจะส่งสตริงเปล่ากลับมา `''` หากกด `key:ESC` มันจะส่ง `null` กลับมา [demo] diff --git a/1-js/02-first-steps/11-logical-operators/article.md b/1-js/02-first-steps/11-logical-operators/article.md index 78c4fd2f1..8e2418a51 100644 --- a/1-js/02-first-steps/11-logical-operators/article.md +++ b/1-js/02-first-steps/11-logical-operators/article.md @@ -1,47 +1,47 @@ -# Logical operators +# ตัวดำเนินการตรรกะ -There are four logical operators in JavaScript: `||` (OR), `&&` (AND), `!` (NOT), `??` (Nullish Coalescing). Here we cover the first three, the `??` operator is in the next article. +ใน JavaScript มีตัวดำเนินการตรรกะ 4 ตัว ได้แก่ `||` (OR), `&&` (AND), `!` (NOT) และ `??` (Nullish Coalescing) ในที่นี้จะอธิบายเฉพาะ 3 ตัวแรก ส่วนตัว `??` จะอยู่ในบทความถัดไป -Although they are called "logical", they can be applied to values of any type, not only boolean. Their result can also be of any type. +แม้จะเรียกว่า "ตรรกะ" แต่ก็สามารถใช้กับค่าประเภทอื่นๆ นอกเหนือจาก boolean ได้ และผลลัพธ์ที่ออกมาก็เป็นประเภทอะไรก็ได้เช่นกัน -Let's see the details. +มาดูรายละเอียดกัน ## || (OR) -The "OR" operator is represented with two vertical line symbols: +เครื่องหมาย "OR" จะแทนด้วยสัญลักษณ์เส้นตั้งคู่ `||` แบบนี้: ```js result = a || b; ``` -In classical programming, the logical OR is meant to manipulate boolean values only. If any of its arguments are `true`, it returns `true`, otherwise it returns `false`. +โดยทั่วไปแล้ว OR ตรรกะมีไว้ใช้กับค่า boolean เท่านั้น ถ้ามี argument ตัวใดเป็น `true` ก็จะคืนค่า `true` ถ้าไม่มีเลยจะคืนค่า `false` -In JavaScript, the operator is a little bit trickier and more powerful. But first, let's see what happens with boolean values. +แต่ใน JavaScript นั้นตัวดำเนินการ OR มีความซับซ้อนและมีพลังมากกว่านั้นหน่อย แต่ก่อนอื่นมาดูว่าเกิดอะไรขึ้นกับค่า boolean ก่อน -There are four possible logical combinations: +จะมีเคสที่เป็นไปได้ 4 แบบ: ```js run alert( true || true ); // true alert( false || true ); // true alert( true || false ); // true -alert( false || false ); // false +alert( false || false ); // false ``` -As we can see, the result is always `true` except for the case when both operands are `false`. +จะเห็นว่าผลลัพธ์จะเป็น `true` เสมอ ยกเว้นกรณีที่ operand ทั้งสองข้างเป็น `false` -If an operand is not a boolean, it's converted to a boolean for the evaluation. +ถ้า operand ไม่ใช่ boolean จะถูกแปลงเป็น boolean ก่อนแล้วค่อยประเมิน -For instance, the number `1` is treated as `true`, the number `0` as `false`: +เช่น ตัวเลข `1` จะถือเป็น `true` ส่วนตัวเลข `0` จะเป็น `false`: ```js run -if (1 || 0) { // works just like if( true || false ) - alert( 'truthy!' ); +if (1 || 0) { // จะทำงานเหมือน if (true || false) + alert('truthy!'); } ``` -Most of the time, OR `||` is used in an `if` statement to test if *any* of the given conditions is `true`. +ส่วนใหญ่แล้ว OR `||` จะใช้ในคำสั่ง `if` เพื่อตรวจว่ามีเงื่อนไขใดเป็น `true` บ้าง -For example: +ตัวอย่างเช่น: ```js run let hour = 9; @@ -49,102 +49,102 @@ let hour = 9; *!* if (hour < 10 || hour > 18) { */!* - alert( 'The office is closed.' ); + alert('ออฟฟิศปิดแล้ว'); } ``` -We can pass more conditions: +เราสามารถเพิ่มเงื่อนไขได้อีก: ```js run let hour = 12; let isWeekend = true; if (hour < 10 || hour > 18 || isWeekend) { - alert( 'The office is closed.' ); // it is the weekend + alert('ออฟฟิศปิดแล้ว'); // เพราะเป็นวันหยุดสุดสัปดาห์ } ``` -## OR "||" finds the first truthy value [#or-finds-the-first-truthy-value] +## OR "||" จะหาค่า truthy ตัวแรก -The logic described above is somewhat classical. Now, let's bring in the "extra" features of JavaScript. +ตรรกะที่อธิบายไว้ข้างต้นค่อนข้างเป็นแบบดั้งเดิม ทีนี้มาดูความสามารถ "พิเศษ" ของ JavaScript กัน -The extended algorithm works as follows. +อัลกอริทึมที่ขยายออกไปจะทำงานดังนี้ -Given multiple OR'ed values: +เมื่อมีหลายค่ามา OR กัน: ```js result = value1 || value2 || value3; ``` -The OR `||` operator does the following: +ตัวดำเนินการ OR `||` จะทำดังนี้: -- Evaluates operands from left to right. -- For each operand, converts it to boolean. If the result is `true`, stops and returns the original value of that operand. -- If all operands have been evaluated (i.e. all were `false`), returns the last operand. +- ประเมิน operand จากซ้ายไปขวา +- สำหรับแต่ละ operand จะแปลงเป็น boolean ถ้าผลลัพธ์เป็น `true` จะหยุดและคืนค่าเดิมของ operand นั้นทันที +- ถ้าประเมิน operand ทั้งหมดแล้ว (คือทุกตัวเป็น `false`) จะคืนค่า operand ตัวสุดท้าย -A value is returned in its original form, without the conversion. +จะคืนค่าในรูปแบบเดิม โดยไม่มีการแปลงใดๆ -In other words, a chain of OR `||` returns the first truthy value or the last one if no truthy value is found. +อีกนัยหนึ่ง การเชื่อม OR `||` หลายตัวจะคืนค่า truthy ตัวแรกเสมอ หรือถ้าไม่เจอค่า truthy เลยจะคืนตัวสุดท้าย -For instance: +ตัวอย่างเช่น: ```js run -alert( 1 || 0 ); // 1 (1 is truthy) +alert( 1 || 0 ); // 1 (1 เป็น truthy) -alert( null || 1 ); // 1 (1 is the first truthy value) -alert( null || 0 || 1 ); // 1 (the first truthy value) +alert( null || 1 ); // 1 (1 เป็นค่า truthy ตัวแรก) +alert( null || 0 || 1 ); // 1 (ค่า truthy ตัวแรก) -alert( undefined || null || 0 ); // 0 (all falsy, returns the last value) +alert( undefined || null || 0 ); // 0 (ทั้งหมดเป็น falsy จึงคืนค่าตัวสุดท้าย) ``` -This leads to some interesting usage compared to a "pure, classical, boolean-only OR". +พฤติกรรมนี้ทำให้มีวิธีใช้ OR ที่น่าสนใจเมื่อเทียบกับการใช้ OR แบบบูลีนอย่างเดียวทั่วไป -1. **Getting the first truthy value from a list of variables or expressions.** +1. **การหาค่า truthy ตัวแรกจาก list ของตัวแปรหรือนิพจน์ต่างๆ** - For instance, we have `firstName`, `lastName` and `nickName` variables, all optional (i.e. can be undefined or have falsy values). + เช่น สมมติเรามีตัวแปร `firstName`, `lastName` และ `nickName` ซึ่งล้วนแต่เป็นออปชันที่อาจจะเป็น undefined หรือมีค่า falsy ได้ - Let's use OR `||` to choose the one that has the data and show it (or `"Anonymous"` if nothing set): + เราสามารถใช้ OR `||` เพื่อเลือกเอาค่าที่เซ็ตข้อมูลแล้วมาแสดง (หรือถ้าไม่มีจะแสดง `"Anonymous"`): - ```js run - let firstName = ""; - let lastName = ""; - let nickName = "SuperCoder"; + ```js run + let firstName = ""; + let lastName = ""; + let nickName = "SuperCoder"; - *!* - alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder - */!* - ``` + *!* + alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder + */!* + ``` - If all variables were falsy, `"Anonymous"` would show up. + ถ้าทุกตัวแปรเป็น falsy ก็จะแสดง `"Anonymous"` -2. **Short-circuit evaluation.** +2. **การประเมินแบบตัดตอนสั้น (short-circuit)** - Another feature of OR `||` operator is the so-called "short-circuit" evaluation. + อีกความสามารถของตัวดำเนินการ OR `||` คือเรียกว่า "short-circuit evaluation" + + มันหมายความว่า `||` จะประมวลผลอาร์กิวเมนต์จนกว่าจะเจอค่า truthy ตัวแรก แล้วจะคืนค่านั้นทันทีเลย โดยไม่แตะอาร์กิวเมนต์ตัวถัดไปเลย - It means that `||` processes its arguments until the first truthy value is reached, and then the value is returned immediately, without even touching the other argument. + ความสำคัญของความสามารถนี้จะเห็นได้ชัดเจน ถ้า operand ไม่ใช่แค่ค่าธรรมดา แต่เป็นนิพจน์ที่มี side-effect อย่างเช่นการกำหนดค่าตัวแปรหรือเรียกใช้ฟังก์ชัน - The importance of this feature becomes obvious if an operand isn't just a value, but an expression with a side effect, such as a variable assignment or a function call. + ในตัวอย่างด้านล่าง จะพิมพ์แค่ข้อความที่สองเท่านั้น: + + ```js run no-beautify + *!*true*/!* || alert("จะไม่พิมพ์"); + *!*false*/!* || alert("จะพิมพ์"); + ``` - In the example below, only the second message is printed: + ในบรรทัดแรก ตัว OR `||` จะหยุดประเมินทันทีที่เจอ `true` ดังนั้น `alert` จึงไม่ถูกเรียก - ```js run no-beautify - *!*true*/!* || alert("not printed"); - *!*false*/!* || alert("printed"); - ``` - - In the first line, the OR `||` operator stops the evaluation immediately upon seeing `true`, so the `alert` isn't run. - - Sometimes, people use this feature to execute commands only if the condition on the left part is falsy. + บางครั้งก็มีคนใช้ความสามารถนี้เพื่อรันคำสั่งก็ต่อเมื่อเงื่อนไขทางซ้ายมือเป็น falsy ด้วย ## && (AND) -The AND operator is represented with two ampersands `&&`: +เครื่องหมาย AND ใช้สัญลักษณ์ & สองตัวติดกัน `&&` แบบนี้: ```js result = a && b; ``` -In classical programming, AND returns `true` if both operands are truthy and `false` otherwise: +โดยปกติในการเขียนโปรแกรม AND จะคืนค่า `true` ถ้า operand ทั้งสองเป็น truthy และคืน `false` ในกรณีอื่นๆ: ```js run alert( true && true ); // true @@ -153,137 +153,135 @@ alert( true && false ); // false alert( false && false ); // false ``` -An example with `if`: +ตัวอย่างการใช้กับ `if`: ```js run let hour = 12; let minute = 30; if (hour == 12 && minute == 30) { - alert( 'The time is 12:30' ); -} + alert( 'ขณะนี้เวลา 12:30 น.' ); +} ``` -Just as with OR, any value is allowed as an operand of AND: +เหมือนกับ OR นั่นคือ operand ของ AND จะเป็นค่าอะไรก็ได้: ```js run -if (1 && 0) { // evaluated as true && false - alert( "won't work, because the result is falsy" ); +if (1 && 0) { // ประเมินเป็น true && false + alert( "จะไม่ทำงาน เพราะผลลัพธ์เป็น falsy" ); } ``` +## AND "&&" จะหาค่า falsy ตัวแรก -## AND "&&" finds the first falsy value - -Given multiple AND'ed values: +ถ้ามีหลายค่ามา AND กัน: ```js result = value1 && value2 && value3; ``` -The AND `&&` operator does the following: +ตัวดำเนินการ AND `&&` จะทำงานดังนี้: -- Evaluates operands from left to right. -- For each operand, converts it to a boolean. If the result is `false`, stops and returns the original value of that operand. -- If all operands have been evaluated (i.e. all were truthy), returns the last operand. +- ประเมิน operand จากซ้ายไปขวา +- สำหรับแต่ละ operand จะแปลงเป็น boolean ถ้าผลลัพธ์เป็น `false` จะหยุดและคืนค่าเดิมของ operand นั้นทันที +- ถ้าประเมิน operand ทั้งหมดแล้ว (คือทุกตัวเป็น truthy) จะคืนค่า operand ตัวสุดท้าย -In other words, AND returns the first falsy value or the last value if none were found. +อีกนัยหนึ่ง AND จะคืนค่า falsy ตัวแรกที่เจอ หรือถ้าไม่เจอเลยจะคืนค่าตัวสุดท้าย -The rules above are similar to OR. The difference is that AND returns the first *falsy* value while OR returns the first *truthy* one. +กฎข้างต้นคล้ายกับ OR ต่างกันตรงที่ AND คืนค่า *falsy* ตัวแรก ส่วน OR คืนค่า *truthy* ตัวแรก -Examples: +ตัวอย่าง: ```js run -// if the first operand is truthy, -// AND returns the second operand: +// ถ้า operand ตัวแรกเป็น truthy +// AND จะคืนค่า operand ตัวที่สอง: alert( 1 && 0 ); // 0 alert( 1 && 5 ); // 5 -// if the first operand is falsy, -// AND returns it. The second operand is ignored +// ถ้า operand ตัวแรกเป็น falsy +// AND จะคืนค่านั้นเลย โดยไม่สนใจ operand ตัวที่สอง alert( null && 5 ); // null -alert( 0 && "no matter what" ); // 0 +alert( 0 && "ไม่สำคัญ" ); // 0 ``` -We can also pass several values in a row. See how the first falsy one is returned: +เราสามารถส่งหลายค่าต่อกันได้ ลองดูว่าค่า falsy ตัวแรกจะถูกคืนออกมา: ```js run alert( 1 && 2 && null && 3 ); // null ``` -When all values are truthy, the last value is returned: +ถ้าค่าทั้งหมดเป็น truthy ค่าตัวสุดท้ายจะถูกคืน: ```js run -alert( 1 && 2 && 3 ); // 3, the last one +alert( 1 && 2 && 3 ); // 3, ตัวสุดท้าย ``` -````smart header="Precedence of AND `&&` is higher than OR `||`" -The precedence of AND `&&` operator is higher than OR `||`. +````smart header="AND `&&` มีลำดับความสำคัญสูงกว่า OR `||`" +ตัวดำเนินการ AND `&&` จะมี precedence สูงกว่า OR `||` -So the code `a && b || c && d` is essentially the same as if the `&&` expressions were in parentheses: `(a && b) || (c && d)`. +ดังนั้นโค้ด `a && b || c && d` ก็เหมือนกับการเขียนนิพจน์ `&&` อยู่ในวงเล็บ: `(a && b) || (c && d)` ```` -````warn header="Don't replace `if` with `||` or `&&`" -Sometimes, people use the AND `&&` operator as a "shorter way to write `if`". +````warn header="อย่าใช้ `||` หรือ `&&` แทนคำสั่ง `if`" +บางครั้งมีคนใช้ตัวดำเนินการ AND `&&` เพื่อ "เขียน `if` ให้สั้นลง" -For instance: +เช่น: ```js run let x = 1; -(x > 0) && alert( 'Greater than zero!' ); +(x > 0) && alert( 'มากกว่าศูนย์!' ); ``` -The action in the right part of `&&` would execute only if the evaluation reaches it. That is, only if `(x > 0)` is true. +การกระทำทางขวาของ `&&` จะรันก็ต่อเมื่อการประเมินทำไปถึงจุดนั้น ซึ่งก็คือเมื่อ `(x > 0)` เป็นจริง -So we basically have an analogue for: +ดังนั้นมันจะเหมือนกับการเขียนแบบนี้: ```js run let x = 1; -if (x > 0) alert( 'Greater than zero!' ); +if (x > 0) alert( 'มากกว่าศูนย์!' ); ``` -Although, the variant with `&&` appears shorter, `if` is more obvious and tends to be a little bit more readable. So we recommend using every construct for its purpose: use `if` if we want `if` and use `&&` if we want AND. +ถึงแม้การใช้ `&&` จะดูสั้นกว่า แต่ `if` จะชัดเจนและอ่านเข้าใจง่ายกว่า แนะนำให้ใช้แต่ละแบบตามวัตถุประสงค์ที่มันถูกสร้างมา ใช้ `if` ถ้าต้องการเงื่อนไข if และใช้ `&&` ถ้าต้องการตรรกะ AND ```` - ## ! (NOT) -The boolean NOT operator is represented with an exclamation sign `!`. +ตัวดำเนินการตรรกะ NOT ใช้สัญลักษณ์อัศเจรีย์ `!` -The syntax is pretty simple: +รูปแบบการใช้งานค่อนข้างง่าย: ```js result = !value; ``` -The operator accepts a single argument and does the following: +โดยตัวดำเนินการจะรับ operand เดียว และทำงานดังนี้: -1. Converts the operand to boolean type: `true/false`. -2. Returns the inverse value. +1. แปลง operand ให้เป็นประเภท boolean: `true/false` +2. คืนค่าตรงข้าม (invert) -For instance: +ตัวอย่างเช่น: ```js run alert( !true ); // false alert( !0 ); // true ``` -A double NOT `!!` is sometimes used for converting a value to boolean type: +การใช้ NOT สองตัวติดกัน `!!` บางครั้งใช้เพื่อแปลงค่าให้เป็นประเภท boolean: ```js run alert( !!"non-empty string" ); // true -alert( !!null ); // false +alert( !!null ); // false ``` -That is, the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again. In the end, we have a plain value-to-boolean conversion. +นั่นคือ NOT ตัวแรกจะแปลงค่าเป็น boolean และคืนค่าตรงข้าม จากนั้น NOT ตัวที่สองก็จะ invert อีกครั้ง ในท้ายที่สุดเราจะได้การแปลงค่าเป็น boolean อย่างง่ายๆ -There's a little more verbose way to do the same thing -- a built-in `Boolean` function: +มีอีกวิธีที่อ่านเข้าใจง่ายกว่าในการทำแบบเดียวกัน คือใช้ฟังก์ชันในตัว `Boolean`: ```js run alert( Boolean("non-empty string") ); // true alert( Boolean(null) ); // false ``` -The precedence of NOT `!` is the highest of all logical operators, so it always executes first, before `&&` or `||`. +ตัวดำเนินการ NOT `!` จะมีลำดับความสำคัญ (precedence) สูงสุดในบรรดาตัวดำเนินการตรรกะทั้งหมด ดังนั้นมันจะถูกประมวลผลก่อนเสมอ ก่อนที่จะไปประมวลผล `&&` หรือ `||` \ No newline at end of file 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 0b2f092ab..854002bc0 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,94 +1,122 @@ -# Nullish coalescing operator '??' +# ตัวดำเนินการรวม Nullish '??' [recent browser="new"] -The nullish coalescing operator is written as two question marks `??`. +ตัวดำเนินการรวม nullish เขียนด้วยเครื่องหมายคำถามสองตัวติดกัน `??` +<<<<<<< HEAD +ในบทความนี้เราจะใช้ศัพท์เฉพาะ เนื่องจาก `null` และ `undefined` ถูกจัดการในลักษณะคล้ายกัน เพื่อให้กระชับ เราจะเรียกว่าค่าหนึ่ง "ถูกกำหนด" เมื่อไม่ใช่ทั้ง `null` และ `undefined` +======= As it treats `null` and `undefined` similarly, we'll use a special term here, in this article. For brevity, we'll say that a value is "defined" when it's neither `null` nor `undefined`. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -The result of `a ?? b` is: -- if `a` is defined, then `a`, -- if `a` isn't defined, then `b`. +ผลลัพธ์ของ `a ?? b` จะเป็น: +- ถ้า `a` ถูกกำหนด ผลลัพธ์คือ `a` +- ถ้า `a` ไม่ถูกกำหนด ผลลัพธ์คือ `b` -In other words, `??` returns the first argument if it's not `null/undefined`. Otherwise, the second one. +อีกนัยหนึ่ง `??` จะคืนอาร์กิวเมนต์ตัวแรก ถ้าไม่ใช่ `null/undefined` ไม่เช่นนั้นจะคืนตัวที่สอง -The nullish coalescing operator isn't anything completely new. It's just a nice syntax to get the first "defined" value of the two. +ตัวดำเนินการรวม nullish ไม่ใช่เรื่องใหม่ เป็นเพียงไวยากรณ์ที่สะดวกในการหาค่าแรกที่ "ถูกกำหนด" จากสองค่า -We can rewrite `result = a ?? b` using the operators that we already know, like this: +เราสามารถเขียน `result = a ?? b` ใหม่โดยใช้ตัวดำเนินการที่คุ้นเคยแล้วได้ดังนี้: ```js result = (a !== null && a !== undefined) ? a : b; ``` -Now it should be absolutely clear what `??` does. Let's see where it helps. +ตอนนี้น่าจะชัดเจนแล้วว่า `??` ทำอะไร มาดูกันว่ามันมีประโยชน์อย่างไรบ้าง +<<<<<<< HEAD +กรณีใช้งานทั่วไปของ `??` คือการกำหนดค่าเริ่มต้น (default) + +ตัวอย่างเช่น ตรงนี้เราจะแสดง `user` ถ้าค่าไม่ใช่ `null/undefined` ไม่อย่างนั้นจะแสดง `Anonymous`: +======= The common use case for `??` is to provide a default value. For example, here we show `user` if its value isn't `null/undefined`, otherwise `Anonymous`: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js run let user; +<<<<<<< HEAD +alert(user ?? "Anonymous"); // Anonymous (user เป็น undefined) +======= alert(user ?? "Anonymous"); // Anonymous (user is undefined) +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ``` -Here's the example with `user` assigned to a name: +นี่คือตัวอย่างที่กำหนด `user` เป็นชื่อ: ```js run let user = "John"; +<<<<<<< HEAD +alert(user ?? "Anonymous"); // John (user ไม่ใช่ null/undefined) +======= alert(user ?? "Anonymous"); // John (user is not null/undefined) +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ``` -We can also use a sequence of `??` to select the first value from a list that isn't `null/undefined`. +เรายังสามารถใช้ `??` หลายตัวต่อกัน เพื่อเลือกค่าแรกจาก list ที่ไม่ใช่ `null/undefined` ได้ด้วย + +<<<<<<< HEAD +สมมติเรามีข้อมูลผู้ใช้ในตัวแปร `firstName`, `lastName` หรือ `nickName` ซึ่งอาจไม่ถูกกำหนดค่า หากผู้ใช้ไม่ได้กรอกข้อมูลที่เกี่ยวข้อง +เราต้องการแสดงชื่อผู้ใช้จากตัวแปรเหล่านี้ตัวใดตัวหนึ่ง หรือแสดง "Anonymous" ถ้าทุกตัวเป็น `null/undefined` +======= Let's say we have a user's data in variables `firstName`, `lastName` or `nickName`. All of them may be not defined, if the user decided not to fill in the corresponding values. We'd like to display the user name using one of these variables, or show "Anonymous" if all of them are `null/undefined`. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Let's use the `??` operator for that: +มาใช้ตัวดำเนินการ `??` กันเลย: ```js run let firstName = null; let lastName = null; let nickName = "Supercoder"; -// shows the first defined value: +// แสดงค่าแรกที่ถูกกำหนด: *!* alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder -*/!* +*/!* ``` -## Comparison with || +## เปรียบเทียบกับ || -The OR `||` operator can be used in the same way as `??`, as it was described in the [previous chapter](info:logical-operators#or-finds-the-first-truthy-value). +ตัวดำเนินการ OR `||` สามารถใช้ได้ในทำนองเดียวกับ `??` ตามที่อธิบายไว้ใน[บทก่อนหน้า](info:logical-operators#or-finds-the-first-truthy-value) -For example, in the code above we could replace `??` with `||` and still get the same result: +เช่น ในโค้ดข้างต้น เราสามารถแทนที่ `??` ด้วย `||` โดยยังได้ผลลัพธ์เหมือนเดิม: ```js run let firstName = null; let lastName = null; let nickName = "Supercoder"; -// shows the first truthy value: +// แสดงค่า truthy ตัวแรก: *!* alert(firstName || lastName || nickName || "Anonymous"); // Supercoder */!* ``` +<<<<<<< HEAD +ย้อนไปในอดีต ตัวดำเนินการ OR `||` มีมาก่อนตั้งแต่ JavaScript เริ่มต้น นักพัฒนาจึงใช้มันเพื่อวัตถุประสงค์แบบนี้มานาน +======= Historically, the OR `||` operator was there first. It's been there since the beginning of JavaScript, so developers were using it for such purposes for a long time. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -On the other hand, the nullish coalescing operator `??` was added to JavaScript only recently, and the reason for that was that people weren't quite happy with `||`. +ในทางกลับกัน ตัวดำเนินการรวม nullish `??` เพิ่งถูกเพิ่มเข้ามาใน JavaScript ไม่นานมานี้ สาเหตุเพราะคนไม่ค่อยพอใจกับ `||` นัก -The important difference between them is that: -- `||` returns the first *truthy* value. -- `??` returns the first *defined* value. +ความแตกต่างสำคัญระหว่างสองตัวนี้คือ: +- `||` คืนค่า *truthy* ตัวแรก +- `??` คืนค่าแรกที่ *ถูกกำหนด* -In other words, `||` doesn't distinguish between `false`, `0`, an empty string `""` and `null/undefined`. They are all the same -- falsy values. If any of these is the first argument of `||`, then we'll get the second argument as the result. +อีกนัยหนึ่ง `||` ไม่ได้แยกความแตกต่างระหว่าง `false`, `0`, string ว่าง `""` และ `null/undefined` มันถือว่าทั้งหมดเป็นค่า falsy เหมือนกัน ถ้าตัวใดตัวหนึ่งเป็น argument ตัวแรกของ `||` เราจะได้ argument ตัวที่สองเป็นผลลัพธ์ -In practice though, we may want to use default value only when the variable is `null/undefined`. That is, when the value is really unknown/not set. +แต่ในทางปฏิบัติ เราอาจต้องการใช้ค่าเริ่มต้นก็ต่อเมื่อตัวแปรเป็น `null/undefined` นั่นคือเมื่อไม่รู้ค่าจริงๆ/ไม่ได้ถูกกำหนด -For example, consider this: +ตัวอย่างเช่น พิจารณาโค้ดนี้: ```js run let height = 0; @@ -97,73 +125,85 @@ alert(height || 100); // 100 alert(height ?? 100); // 0 ``` -- The `height || 100` checks `height` for being a falsy value, and it's `0`, falsy indeed. - - so the result of `||` is the second argument, `100`. -- The `height ?? 100` checks `height` for being `null/undefined`, and it's not, - - so the result is `height` "as is", that is `0`. +- `height || 100` ตรวจสอบว่า `height` เป็นค่า falsy หรือไม่ ซึ่ง `0` ก็ถือเป็น falsy จริงๆ + - ดังนั้นผลลัพธ์ของ `||` คือ argument ตัวที่สอง `100` +- `height ?? 100` ตรวจสอบว่า `height` เป็น `null/undefined` หรือไม่ ซึ่งไม่ใช่ + - ดังนั้นผลลัพธ์คือ `height` "ตามที่เป็น" คือ `0` -In practice, the zero height is often a valid value, that shouldn't be replaced with the default. So `??` does just the right thing. +ในทางปฏิบัติ ความสูงเป็นศูนย์มักเป็นค่าที่ถูกต้อง ไม่ควรถูกแทนที่ด้วยค่าเริ่มต้น ดังนั้น `??` จึงให้ผลลัพธ์ที่ถูกต้องพอดี -## Precedence +## ลำดับความสำคัญ +<<<<<<< HEAD +ตัวดำเนินการ `??` มีลำดับความสำคัญเท่ากับ `||` ทั้งคู่มีค่าเท่ากับ `3` ในตาราง [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table) +======= The precedence of the `??` operator is the same as `||`. They both equal `3` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table). +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -That means that, just like `||`, the nullish coalescing operator `??` is evaluated before `=` and `?`, but after most other operations, such as `+`, `*`. +นั่นหมายความว่า เช่นเดียวกับ `||` ตัวดำเนินการรวม nullish `??` จะถูกประเมินก่อน `=` และ `?` แต่หลังการดำเนินการอื่นๆ ส่วนใหญ่ เช่น `+`, `*` +<<<<<<< HEAD +ดังนั้นในนิพจน์แบบนี้ เราอาจต้องใส่วงเล็บเพิ่ม: +======= So we may need to add parentheses in expressions like this: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js run let height = null; let width = null; -// important: use parentheses +// สำคัญ: ใช้วงเล็บ let area = (height ?? 100) * (width ?? 50); alert(area); // 5000 ``` -Otherwise, if we omit parentheses, then as `*` has the higher precedence than `??`, it would execute first, leading to incorrect results. +ไม่เช่นนั้น ถ้าเราละวงเล็บ เนื่องจาก `*` มีลำดับความสำคัญสูงกว่า `??` มันจะถูกประเมินก่อน ทำให้ได้ผลลัพธ์ไม่ถูกต้อง ```js -// without parentheses +// ไม่มีวงเล็บ let area = height ?? 100 * width ?? 50; +<<<<<<< HEAD +// ...ทำงานแบบนี้ (ไม่ใช่สิ่งที่เราต้องการ): +======= // ...works this way (not what we want): +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 let area = height ?? (100 * width) ?? 50; ``` -### Using ?? with && or || +### การใช้ ?? ร่วมกับ && หรือ || -Due to safety reasons, JavaScript forbids using `??` together with `&&` and `||` operators, unless the precedence is explicitly specified with parentheses. +ด้วยเหตุผลด้านความปลอดภัย JavaScript ไม่อนุญาตให้ใช้ `??` ร่วมกับตัวดำเนินการ `&&` และ `||` นอกจากจะระบุลำดับความสำคัญชัดเจนด้วยวงเล็บ -The code below triggers a syntax error: +โค้ดด้านล่างจะทำให้เกิด syntax error: ```js run let x = 1 && 2 ?? 3; // Syntax error ``` -The limitation is surely debatable, it was added to the language specification with the purpose to avoid programming mistakes, when people start to switch from `||` to `??`. +ข้อจำกัดนี้อาจโต้แย้งได้ แต่ถูกเพิ่มเข้ามาในข้อกำหนดภาษา เพื่อหลีกเลี่ยงข้อผิดพลาดในการเขียนโปรแกรม เมื่อคนเริ่มเปลี่ยนจาก `||` มาใช้ `??` -Use explicit parentheses to work around it: +ใช้วงเล็บให้ชัดเจนเพื่อแก้ปัญหา: ```js run *!* -let x = (1 && 2) ?? 3; // Works +let x = (1 && 2) ?? 3; // ใช้ได้ */!* alert(x); // 2 ``` -## Summary +## สรุป -- The nullish coalescing operator `??` provides a short way to choose the first "defined" value from a list. +- ตัวดำเนินการรวม nullish `??` ให้วิธีที่กระชับในการเลือกค่าแรกที่ "ถูกกำหนด" จาก list - It's used to assign default values to variables: + มันมักถูกใช้เพื่อกำหนดค่าเริ่มต้นให้ตัวแปร: - ```js - // set height=100, if height is null or undefined - height = height ?? 100; - ``` + ```js + // กำหนด height=100 ถ้า height เป็น null หรือ undefined + height = height ?? 100; + ``` -- The operator `??` has a very low precedence, only a bit higher than `?` and `=`, so consider adding parentheses when using it in an expression. -- It's forbidden to use it with `||` or `&&` without explicit parentheses. +- ตัวดำเนินการ `??` มีลำดับความสำคัญต่ำมาก สูงกว่า `?` และ `=` เพียงเล็กน้อย ดังนั้นควรใส่วงเล็บเมื่อใช้ในนิพจน์ +- ห้ามใช้ร่วมกับ `||` หรือ `&&` โดยไม่ใส่วงเล็บให้ชัดเจน \ No newline at end of file diff --git a/1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md b/1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md index 43ee4aad3..ffc37a316 100644 --- a/1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md +++ b/1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md @@ -1,4 +1,4 @@ -The answer: `1`. +คำตอบก็คือ `1`. ```js run let i = 3; @@ -8,18 +8,18 @@ while (i) { } ``` -Every loop iteration decreases `i` by `1`. The check `while(i)` stops the loop when `i = 0`. +การวนซ้ำแต่ละครั้งค่าของตัวแปร `i` จะลดลงทีละ `1` ฉะนั้น `while (i)` จะหยุดเมื่อ `i = 0` -Hence, the steps of the loop form the following sequence ("loop unrolled"): +ดังนั้นขั้นตอนการทำงานจึงเป็นไปตามด้านล่างนี้ ("loop unrolled") ```js let i = 3; -alert(i--); // shows 3, decreases i to 2 +alert(i--); // แสดง 3 ลด i เป็น 2 -alert(i--) // shows 2, decreases i to 1 +alert(i--) // แสดง 2 ลด i เป็น 1 -alert(i--) // shows 1, decreases i to 0 +alert(i--) // แสดง 1 ลด i เป็น 0 -// done, while(i) check stops the loop +// จบการทำงาน ``` diff --git a/1-js/02-first-steps/13-while-for/1-loop-last-value/task.md b/1-js/02-first-steps/13-while-for/1-loop-last-value/task.md index 3b847dfa2..bb5c9b337 100644 --- a/1-js/02-first-steps/13-while-for/1-loop-last-value/task.md +++ b/1-js/02-first-steps/13-while-for/1-loop-last-value/task.md @@ -2,9 +2,9 @@ importance: 3 --- -# Last loop value +# ทายเลขตัวสุดท้าย -What is the last value alerted by this code? Why? +คิดว่าเลขตัวสุดท้ายที่จะแสดงผลจากฟังก์ชัน `alert` คือเลขอะไร ```js let i = 3; diff --git a/1-js/02-first-steps/13-while-for/2-which-value-while/solution.md b/1-js/02-first-steps/13-while-for/2-which-value-while/solution.md index 495359876..6611b0348 100644 --- a/1-js/02-first-steps/13-while-for/2-which-value-while/solution.md +++ b/1-js/02-first-steps/13-while-for/2-which-value-while/solution.md @@ -1,30 +1,30 @@ -The task demonstrates how postfix/prefix forms can lead to different results when used in comparisons. +วิธีนี้จะช่วยให้เห็นว่าการเติม postfix/prefix สามารถให้ผลลัพธ์ที่แตกต่างกันได้ หากใช้ในการเปรียบเทียบ -1. **From 1 to 4** +1. **จาก 1 ไป 4** ```js run let i = 0; while (++i < 5) alert( i ); ``` - The first value is `i = 1`, because `++i` first increments `i` and then returns the new value. So the first comparison is `1 < 5` and the `alert` shows `1`. + ค่าแรกคือ `i = 1`, การ prefix `++i` คือบวกเพิ่มทีละหนึ่งก่อนค่อยส่งค่า**ใหม่**กลับ ดังนั้นเมื่อเทียบเงื่อนไขก็จะเป็น `1 < 5` ฟังก์ชัน `alert` จึงแสดงเลข `1` - Then follow `2, 3, 4…` -- the values show up one after another. The comparison always uses the incremented value, because `++` is before the variable. + จากนั้นตามด้วย `2, 3, 4…` ค่าจะแสดงเพิ่มขึ้นทีละ 1 ในขณะเดียวกัน - Finally, `i = 4` is incremented to `5`, the comparison `while(5 < 5)` fails, and the loop stops. So `5` is not shown. -2. **From 1 to 5** + จนไปถึง `i = 4` ค่าถูกเพิ่มไปที่ `5` เมื่อเทียบเปรียบจะได้ `while(5 < 5)` ซึ่งเป็นเท็จ ลูบจะหยุดทำงาน เลข `5` จึงไม่แสดงออกมา +2. **จาก 1 ไป 5** ```js run let i = 0; while (i++ < 5) alert( i ); ``` - The first value is again `i = 1`. The postfix form of `i++` increments `i` and then returns the *old* value, so the comparison `i++ < 5` will use `i = 0` (contrary to `++i < 5`). + ค่าแรกคือ `i = 1` การ postfix `i++` คือบวก `i` เพิ่มทีละหนึ่งแต่กลับค่า**เก่า**กลับ ดังนั้นเมื่อเทียบเงื่อนไข `i++ < 5` ก็จะเป็น `i = 0` (ตรงข้ามกับ `++i < 5`) - But the `alert` call is separate. It's another statement which executes after the increment and the comparison. So it gets the current `i = 1`. + แต่ฟังก์ชัน `alert` ถูกเรียกแยกตะหาก มันเป็นอีกคำสั่งหนึ่งซึ่งถูกเรียกหลังจากที่ตัวแปร `i` ถูกบวกค่าเพิ่มเข้าไปแล้ว จึงทำให้ตอนนี้ตัวแปร `i = 1` - Then follow `2, 3, 4…` + จากนั้นก็ตามด้วย `2, 3, 4…` - Let's stop on `i = 4`. The prefix form `++i` would increment it and use `5` in the comparison. But here we have the postfix form `i++`. So it increments `i` to `5`, but returns the old value. Hence the comparison is actually `while(4 < 5)` -- true, and the control goes on to `alert`. + มาหยุดตรงที่ตอน `i = 4` ไปก่อน เราเห็นจากข้างบนแล้วว่าการเติม prefix `++i` เพิ่มค่าให้ `i` ทีละหนึ่งซึ่งจะทำให้ใช้เลข `5` เป็นตัวเทียบเปรียบ แต่สำหรับการเติม postfix `i++` มันก็ทำงานแบบเดียวกันคือตัวแปร `i` เป็น `5` แต่มันจะส่งค่าเก่ากลับไป ดังนั้นเมื่อเปรียบเทียบจึงกลายเป็น `while(4 < 5)` -- ซึ่งเงื่อนไขเป็นจริง ทำให้ลูบทำงานต่อ - The value `i = 5` is the last one, because on the next step `while(5 < 5)` is false. + จนวนกลับมาอีกรอบทีนี้ `i = 5` แล้ว เงื่อนไข `while(5 < 5)` จึงเป็นเท็จ ลูบจึงหยุดทำงาน diff --git a/1-js/02-first-steps/13-while-for/2-which-value-while/task.md b/1-js/02-first-steps/13-while-for/2-which-value-while/task.md index 298213237..3d082b10f 100644 --- a/1-js/02-first-steps/13-while-for/2-which-value-while/task.md +++ b/1-js/02-first-steps/13-while-for/2-which-value-while/task.md @@ -2,19 +2,19 @@ importance: 4 --- -# Which values does the while loop show? +# ทายกันว่าจะมีเลขอะไรออกมาบ้าง -For every loop iteration, write down which value it outputs and then compare it with the solution. +ลองหยิบกระดาศขึ้นมาหนึ่งแผ่น เขียนตัวเลขที่คิดว่าจะแสดงผลออกมาจากโค้ดด้านล่าง และตอบคำถามด้านล่าง -Both loops `alert` the same values, or not? +ทั้งสองลูบแสดงผลลัพธ์เดียวกันหรือไม่ -1. The prefix form `++i`: +1. เติม prefix `++i`: ```js let i = 0; while (++i < 5) alert( i ); ``` -2. The postfix form `i++` +2. เติม postfix `i++` ```js let i = 0; diff --git a/1-js/02-first-steps/13-while-for/3-which-value-for/solution.md b/1-js/02-first-steps/13-while-for/3-which-value-for/solution.md index e2e28e75b..f997c4d2b 100644 --- a/1-js/02-first-steps/13-while-for/3-which-value-for/solution.md +++ b/1-js/02-first-steps/13-while-for/3-which-value-for/solution.md @@ -1,4 +1,4 @@ -**The answer: from `0` to `4` in both cases.** +**คำตอบ: แสดงจาก `0` ถึง `4` ทั้งสองกรณี** ```js run for (let i = 0; i < 5; ++i) alert( i ); @@ -6,12 +6,12 @@ for (let i = 0; i < 5; ++i) alert( i ); for (let i = 0; i < 5; i++) alert( i ); ``` -That can be easily deducted from the algorithm of `for`: +มาดูวิธีการทำงานของลูบ `for` กัน: -1. Execute once `i = 0` before everything (begin). -2. Check the condition `i < 5` -3. If `true` -- execute the loop body `alert(i)`, and then `i++` +1. มันทำงานเริ่มจากให้ `i = 0` ก่อน +2. จากนั่นก็ไปตรวจสอบเงื่อนไข `i < 5` +3. ถ้าเป็น `true` -- โค้ดที่อยู่ข้างในลูบจะทำงาน `alert(i)` และตามด้วย `i++` -The increment `i++` is separated from the condition check (2). That's just another statement. +จะเห็นว่าการเพิ่มทีละหนึ่ง `i++` ทำงานทีหลังการตรวจสอบเงื่อนไข (2). มันเป็นอีกหนึ่งคำสั่ง -The value returned by the increment is not used here, so there's no difference between `i++` and `++i`. +ดังนั้นค่าที่คืนมาจากการเพิ่มละหนึ่งไม่ว่าแบบ `postfix` หรือ `prefix` ไม่ได้ถูกใช้ ดังนั้นจึงไม่มีความแตกต่างกันระหว่าง `i++` และ `++i` diff --git a/1-js/02-first-steps/13-while-for/3-which-value-for/task.md b/1-js/02-first-steps/13-while-for/3-which-value-for/task.md index bfefa63f5..3ee1947e1 100644 --- a/1-js/02-first-steps/13-while-for/3-which-value-for/task.md +++ b/1-js/02-first-steps/13-while-for/3-which-value-for/task.md @@ -2,18 +2,18 @@ importance: 4 --- -# Which values get shown by the "for" loop? +# ทายผลลัพธ์อะไรที่จะแสดงออกจากลูบ "for" -For each loop write down which values it is going to show. Then compare with the answer. +ลองมาเขียนผลลัพธ์ที่จะแสดงออกมาในแต่ละรอบการทำงานกัน -Both loops `alert` same values or not? +ทั้งสองลูบฟังก์ชัน `alert` จะแสดงค่าออกมาเหมือนกันหรือไม่ -1. The postfix form: +1. แบบ postfix: ```js for (let i = 0; i < 5; i++) alert( i ); ``` -2. The prefix form: +2. แบบ prefix: ```js for (let i = 0; i < 5; ++i) alert( i ); diff --git a/1-js/02-first-steps/13-while-for/4-for-even/solution.md b/1-js/02-first-steps/13-while-for/4-for-even/solution.md index e8e66bb47..b1c4a0e6c 100644 --- a/1-js/02-first-steps/13-while-for/4-for-even/solution.md +++ b/1-js/02-first-steps/13-while-for/4-for-even/solution.md @@ -8,4 +8,4 @@ for (let i = 2; i <= 10; i++) { } ``` -We use the "modulo" operator `%` to get the remainder and check for the evenness here. +เราใช้ตัวดำเนินการ "modulo" หรือ `%` เพื่อดูเศษที่เหลือจากการหาร ในทีนี้คือ สองหาร `i` เหลือเศษเป็น `0` หรือไม่ หากเป็นจริงฟังก์ชัน `alert` จะทำงาน diff --git a/1-js/02-first-steps/13-while-for/4-for-even/task.md b/1-js/02-first-steps/13-while-for/4-for-even/task.md index ff34e7e40..7f9ac2e15 100644 --- a/1-js/02-first-steps/13-while-for/4-for-even/task.md +++ b/1-js/02-first-steps/13-while-for/4-for-even/task.md @@ -2,8 +2,8 @@ importance: 5 --- -# Output even numbers in the loop +# มาลองเขียนลูบที่แสดงผลเฉพาะเลขคู่กัน -Use the `for` loop to output even numbers from `2` to `10`. +มาลองเขียนลูบ `for` ที่แสดงผลจากเลข `2` ไป `10` กัน [demo] diff --git a/1-js/02-first-steps/13-while-for/5-replace-for-while/task.md b/1-js/02-first-steps/13-while-for/5-replace-for-while/task.md index 0c69d9c2d..745013bf0 100644 --- a/1-js/02-first-steps/13-while-for/5-replace-for-while/task.md +++ b/1-js/02-first-steps/13-while-for/5-replace-for-while/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Replace "for" with "while" +# มาลองเปลี่ยนจากลูบ "for" เป็นลูบ "while" กัน -Rewrite the code changing the `for` loop to `while` without altering its behavior (the output should stay same). +มาลองเขียนโค้ดใหม่จากลูบ "for" ด้านล่างให้มาเป็นลูบ "while" กัน โดยที่ผลลัพธ์ควรเหมือนเดิม ```js run for (let i = 0; i < 3; i++) { diff --git a/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md index c7de5f09b..5ef93f4b8 100644 --- a/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md +++ b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md @@ -7,9 +7,9 @@ do { } while (num <= 100 && num); ``` -The loop `do..while` repeats while both checks are truthy: +เราใช้ลูบ `do..while` เพื่อให้มันทำงานจนกว่าเงื่อนไขจะเป็นเท็จ -1. The check for `num <= 100` -- that is, the entered value is still not greater than `100`. -2. The check `&& num` is false when `num` is `null` or an empty string. Then the `while` loop stops too. +1. ตรวจสอบว่า `num <= 100` +2. ตรวจสอบอีกชั้นด้วย `&& num` หาก `num` เป็น falsy value เช่น `null` หรือสตริงเปล่า ลูบ `while` ก็จะหยุดทำงาน -P.S. If `num` is `null` then `num <= 100` is `true`, so without the 2nd check the loop wouldn't stop if the user clicks CANCEL. Both checks are required. +ปล. หากตัวแปร `num` เป็น `null` เมื่อเทียบว่า `num <= 100` จะเป็นจริง `true` นั่นก็เพราะว่า หากเป็นการเปรียบเทียบ `null` จะถูกแปลงเป็นตัวเลขซึ่งก็คือศูนย์ ดูคุ้นๆไหม ดังนั้นหากเราไม่มีการตรวจสอบ 2 ชั้น ลูบจะไม่หยุดทำงานจนกว่าผู้ใช้จะกด CANCEL เราจึงจำเป็นต้องมีการตรวจสอบชั้น 2 ด้วย diff --git a/1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md index 0788ee76e..d488cce56 100644 --- a/1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md +++ b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md @@ -2,12 +2,12 @@ importance: 5 --- -# Repeat until the input is correct +# มาลองเขียนลูบที่ถามผู้ใช้ไปเรื่อยๆจนกว่าจะป้อนข้อความที่ถูกต้องกัน -Write a loop which prompts for a number greater than `100`. If the visitor enters another number -- ask them to input again. +เขียนลูบที่ให้ผู้ใช้ป้อนตัวเลขมากกว่า `100` หากผู้ใช้ป้อนตัวเลขที่ต่ำกว่าก็ให้ถามผู้ใช้ไปเรื่อยๆจนกว่าจะป้อนถูก -The loop must ask for a number until either the visitor enters a number greater than `100` or cancels the input/enters an empty line. +ลูบจะต้องวนซ้ำไปเรื่อยๆจนกว่าผู้ใช้จะป้อนตัวเลขมากกว่า `100` หรือยกเลิกการป้อนข้อมูลหรือป้อนบรรทัดว่าง -Here we can assume that the visitor only inputs numbers. There's no need to implement a special handling for a non-numeric input in this task. +เราจะให้ผู้ใช้ป้อนเฉพาะตัวเลขเท่านั้น ดังนั้นไม่จำเป็นต้องเขียนแปลงชนิดของข้อมูลอื่นๆให้เป็นตัวเลข [demo] diff --git a/1-js/02-first-steps/13-while-for/7-list-primes/solution.md b/1-js/02-first-steps/13-while-for/7-list-primes/solution.md index b4b64b6fa..1a233404b 100644 --- a/1-js/02-first-steps/13-while-for/7-list-primes/solution.md +++ b/1-js/02-first-steps/13-while-for/7-list-primes/solution.md @@ -1,6 +1,6 @@ -There are many algorithms for this task. +สำหรับการบ้านนี้เราสามารถทำได้หลากหลายวิธี -Let's use a nested loop: +ลองมาเริ่มจากใช้ลูบซ้อนลูบก่อน: ```js For each i in the interval { @@ -10,7 +10,7 @@ For each i in the interval { } ``` -The code using a label: +ลองใช้ label: ```js run let n = 10; @@ -19,11 +19,11 @@ nextPrime: for (let i = 2; i <= n; i++) { // for each i... for (let j = 2; j < i; j++) { // look for a divisor.. - if (i % j == 0) continue nextPrime; // not a prime, go next i + if (i % j == 0) continue nextPrime; // หากไม่เป็นจำนวนเฉพาะ ไป i ตัวต่อไป } - alert( i ); // a prime + alert( i ); // ตรงนี้จะได้จำนวนเฉพาะ } ``` -There's a lot of space to optimize it. For instance, we could look for the divisors from `2` to square root of `i`. But anyway, if we want to be really efficient for large intervals, we need to change the approach and rely on advanced maths and complex algorithms like [Quadratic sieve](https://en.wikipedia.org/wiki/Quadratic_sieve), [General number field sieve](https://en.wikipedia.org/wiki/General_number_field_sieve) etc. +มีวิธีมากมายที่ช่วยเพิ่มประสิทธิภาพให้กับโค้ดชุดนี้ เมื่อ `n` ใหญ่ขึ้น เช่น เราสามารถมองหาตัวหารจาก `2` ถึงรากที่สองของ `i` แต่อย่างไรก็ตามหาก `n` ของเราใหญ่มากๆ เราก็จำเป้นที่จะต้องใช้วิธีการที่ซับซ้อนมากขึ้น เพื่อให้โปรแกรมทำงานได้มีประสิทธิภาพสูงสุด โดยอาศัยหลักการทางคณิตศาสตร์และอัลกอรึทึ่มเข้าช่วยเช่น [Quadratic sieve](https://en.wikipedia.org/wiki/Quadratic_sieve), [General number field sieve](https://en.wikipedia.org/wiki/General_number_field_sieve) และอื่นๆ diff --git a/1-js/02-first-steps/13-while-for/7-list-primes/task.md b/1-js/02-first-steps/13-while-for/7-list-primes/task.md index 6344b9f6f..f0a7a00dd 100644 --- a/1-js/02-first-steps/13-while-for/7-list-primes/task.md +++ b/1-js/02-first-steps/13-while-for/7-list-primes/task.md @@ -2,16 +2,16 @@ importance: 3 --- -# Output prime numbers +# แสดงจำนวนเฉพาะ (prime numbers) -An integer number greater than `1` is called a [prime](https://en.wikipedia.org/wiki/Prime_number) if it cannot be divided without a remainder by anything except `1` and itself. +เราจะเรียกจำนวนเต็มที่มากกว่า `1` และไม่สามารถหารเลขอื่นลงตัวได้ (ไม่มีเศษ) ยกเว้น `1` กับตัวมันเองว่า[จำนวนเฉพาะ](https://en.wikipedia.org/wiki/Prime_number) -In other words, `n > 1` is a prime if it can't be evenly divided by anything except `1` and `n`. +หรือก็คือเมื่อ `n > 1` จะเป็นจำนวนเฉพาะหาก `n` ไม่สามารถหารเลขอื่นลงตัวได้ ยกเว้น `1` กับ `n` -For example, `5` is a prime, because it cannot be divided without a remainder by `2`, `3` and `4`. +ตัวอย่าง `5` เป็นจำนวนเฉพาะ เพราะว่า `5` ไม่สามารถหาร `2`, `3` และ `4` ลงตัวได้ -**Write the code which outputs prime numbers in the interval from `2` to `n`.** +**จงเขียนโค้ดที่แสดงจำนวนเฉพาะจาก `2` ถึง `n`** -For `n = 10` the result will be `2,3,5,7`. +หาก `n = 10` ผลลัพธ์ที่ได้ควรเป็น `2,3,5,7`. -P.S. The code should work for any `n`, not be hard-tuned for any fixed value. +ปล. โค้ดที่เขียนควรใช้ได้กับ `n` ที่เป็นเลขจำนวนเต็มใดๆก็ได้ diff --git a/1-js/02-first-steps/13-while-for/article.md b/1-js/02-first-steps/13-while-for/article.md index d1b749888..e25cce768 100644 --- a/1-js/02-first-steps/13-while-for/article.md +++ b/1-js/02-first-steps/13-while-for/article.md @@ -1,11 +1,15 @@ -# Loops: while and for +# ลูป: while และ for -We often need to repeat actions. +เราต้องทำซ้ำการกระทำบางอย่างบ่อยๆ -For example, outputting goods from a list one after another or just running the same code for each number from 1 to 10. +ตัวอย่างเช่น แสดงผลสินค้าจากรายการทีละชิ้น หรืออาจเป็นแค่การรันโค้ดเดิมซ้ำๆ สำหรับทุกตัวเลขตั้งแต่ 1 ถึง 10 -*Loops* are a way to repeat the same code multiple times. +*ลูป* คือวิธีการทำให้โค้ดทำงานซ้ำหลายรอบ +<<<<<<< HEAD +````smart header="ลูป for..of และ for..in" +ข้อความสำหรับผู้อ่านระดับสูงเล็กน้อย +======= ```smart header="The for..of and for..in loops" A small announcement for advanced readers. @@ -20,60 +24,72 @@ Otherwise, please read on. ``` ## The "while" loop +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -The `while` loop has the following syntax: +บทความนี้จะกล่าวถึงเฉพาะลูปพื้นฐาน ได้แก่ `while`, `do..while` และ `for(..;..;..)` + +หากคุณมาที่บทความนี้เพื่อหาข้อมูลเกี่ยวกับลูปประเภทอื่นๆ สามารถดูได้จาก: + +- [for..in](info:object#forin) สำหรับการวนลูปเพื่อเข้าถึงพร็อพเพอร์ตี้ของออบเจ็กต์ +- [for..of](info:array#loops) และ [iterable](info:iterable) สำหรับการวนลูปอาร์เรย์และออบเจ็กต์ที่สามารถวนซ้ำได้ (iterable objects) + +หากไม่ใช่ กรุณาอ่านต่อไปได้เลยครับ +```` + +## ลูป "while" + +ลูป `while` มีไวยากรณ์ดังนี้: ```js while (condition) { - // code - // so-called "loop body" + // โค้ด + // เรียกว่า "loop body" } ``` -While the `condition` is truthy, the `code` from the loop body is executed. +ตราบใดที่ `condition` เป็นจริง `code` ใน loop body จะถูกประมวลผล -For instance, the loop below outputs `i` while `i < 3`: +ยกตัวอย่างเช่น ลูปด้านล่างจะแสดงค่า `i` ตราบเท่าที่ `i < 3`: ```js run let i = 0; -while (i < 3) { // shows 0, then 1, then 2 +while (i < 3) { // แสดง 0, แล้ว 1, แล้ว 2 alert( i ); i++; } ``` -A single execution of the loop body is called *an iteration*. The loop in the example above makes three iterations. +การประมวลผล loop body หนึ่งรอบเรียกว่า *การวนซ้ำ (iteration)* ลูปในตัวอย่างข้างต้นทำการวนซ้ำสามรอบ -If `i++` was missing from the example above, the loop would repeat (in theory) forever. In practice, the browser provides ways to stop such loops, and in server-side JavaScript, we can kill the process. +หากไม่มีคำสั่ง `i++` ในตัวอย่างข้างต้น ลูปจะทำซ้ำ (ในทางทฤษฎี) ไปเรื่อยๆ ในทางปฏิบัติ เบราว์เซอร์จะมีวิธีหยุดลูปเช่นนี้ และใน JavaScript ฝั่งเซิร์ฟเวอร์ เราสามารถยุติกระบวนการได้ -Any expression or variable can be a loop condition, not just comparisons: the condition is evaluated and converted to a boolean by `while`. +เงื่อนไขลูปสามารถเป็นนิพจน์หรือตัวแปรใดๆ ก็ได้ ไม่จำเป็นต้องเป็นการเปรียบเทียบเท่านั้น: `while` จะประเมินเงื่อนไขและแปลงเป็นบูลีน -For instance, a shorter way to write `while (i != 0)` is `while (i)`: +ตัวอย่างเช่น วิธีที่สั้นกว่าในการเขียน `while (i != 0)` คือ `while (i)`: ```js run let i = 3; *!* -while (i) { // when i becomes 0, the condition becomes falsy, and the loop stops +while (i) { // เมื่อ i เป็น 0, เงื่อนไขจะเป็นเท็จ และลูปจะหยุด */!* alert( i ); i--; } ``` -````smart header="Curly braces are not required for a single-line body" -If the loop body has a single statement, we can omit the curly braces `{…}`: +````smart header="ไม่จำเป็นต้องใช้วงเล็บปีกกาสำหรับ loop body ที่มีคำสั่งเดียว" +หาก loop body มีเพียงคำสั่งเดียว เราสามารถละวงเล็บปีกกา `{…}` ได้: ```js run let i = 3; *!* while (i) alert(i--); */!* -``` ```` -## The "do..while" loop +## ลูป "do..while" -The condition check can be moved *below* the loop body using the `do..while` syntax: +เราสามารถย้ายการตรวจสอบเงื่อนไขไปอยู่*ด้านล่าง*ของ loop body ได้ด้วยการใช้ไวยากรณ์ `do..while`: ```js do { @@ -81,9 +97,9 @@ do { } while (condition); ``` -The loop will first execute the body, then check the condition, and, while it's truthy, execute it again and again. +ลูปจะทำการประมวลผล body ก่อน จากนั้นจึงตรวจสอบเงื่อนไข และหากเงื่อนไขเป็นจริง ก็จะประมวลผลซ้ำไปเรื่อยๆ -For example: +ตัวอย่างเช่น: ```js run let i = 0; @@ -93,13 +109,13 @@ do { } while (i < 3); ``` -This form of syntax should only be used when you want the body of the loop to execute **at least once** regardless of the condition being truthy. Usually, the other form is preferred: `while(…) {…}`. +ไวยากรณ์ในรูปแบบนี้ควรใช้เฉพาะเมื่อต้องการให้ body ของลูปทำงาน**อย่างน้อยหนึ่งครั้ง** โดยไม่คำนึงว่าเงื่อนไขจะเป็นจริงหรือไม่ โดยทั่วไปแล้วมักจะนิยมใช้รูปแบบอื่นมากกว่า เช่น `while(…) {…}` -## The "for" loop +## ลูป "for" -The `for` loop is more complex, but it's also the most commonly used loop. +ลูป `for` มีความซับซ้อนกว่า แต่ก็เป็นลูปที่ใช้บ่อยที่สุดเช่นกัน -It looks like this: +รูปแบบของมันเป็นดังนี้: ```js for (begin; condition; step) { @@ -107,24 +123,24 @@ for (begin; condition; step) { } ``` -Let's learn the meaning of these parts by example. The loop below runs `alert(i)` for `i` from `0` up to (but not including) `3`: +มาทำความเข้าใจความหมายของแต่ละส่วนผ่านตัวอย่างกัน ลูปด้านล่างจะรัน `alert(i)` สำหรับ `i` ตั้งแต่ `0` ถึง (แต่ไม่รวม) `3`: ```js run -for (let i = 0; i < 3; i++) { // shows 0, then 1, then 2 +for (let i = 0; i < 3; i++) { // แสดง 0, แล้ว 1, แล้ว 2 alert(i); } ``` -Let's examine the `for` statement part-by-part: +มาดูประโยค `for` ทีละส่วนกัน: -| part | | | +| ส่วน | | | |-------|----------|----------------------------------------------------------------------------| -| begin | `let i = 0` | Executes once upon entering the loop. | -| condition | `i < 3`| Checked before every loop iteration. If false, the loop stops. | -| body | `alert(i)`| Runs again and again while the condition is truthy. | -| step| `i++` | Executes after the body on each iteration. | +| begin | `let i = 0` | ทำงานครั้งเดียวเมื่อเริ่มเข้าลูป | +| condition | `i < 3`| ตรวจสอบก่อนการวนลูปทุกรอบ ถ้าเป็นเท็จ ลูปจะหยุด | +| body | `alert(i)`| ทำซ้ำไปเรื่อยๆ ตราบเท่าที่เงื่อนไขเป็นจริง | +| step| `i++` | ทำงานหลัง body ในแต่ละรอบ | -The general loop algorithm works like this: +ขั้นตอนการทำงานของลูปโดยทั่วไปเป็นดังนี้: ``` Run begin @@ -134,11 +150,11 @@ Run begin → ... ``` -That is, `begin` executes once, and then it iterates: after each `condition` test, `body` and `step` are executed. +นั่นคือ `begin` จะถูกรันครั้งเดียว จากนั้นจะเริ่มวนลูป: หลังจากตรวจสอบ `condition` แต่ละครั้ง `body` และ `step` จะถูกประมวลผล -If you are new to loops, it could help to go back to the example and reproduce how it runs step-by-step on a piece of paper. +ถ้าคุณเพิ่งเริ่มเรียนรู้เรื่องลูป การย้อนกลับไปดูตัวอย่างและลองเขียนเองทีละขั้นตอนบนกระดาษอาจช่วยทำความเข้าใจได้ดีขึ้น -Here's exactly what happens in our case: +ต่อไปนี้คือสิ่งที่เกิดขึ้นจริงๆ ในกรณีของเรา: ```js // for (let i = 0; i < 3; i++) alert(i) @@ -154,46 +170,51 @@ if (i < 3) { alert(i); i++ } // ...finish, because now i == 3 ``` -````smart header="Inline variable declaration" -Here, the "counter" variable `i` is declared right in the loop. This is called an "inline" variable declaration. Such variables are visible only inside the loop. +```smart header="การประกาศตัวแปรอินไลน์" +ในที่นี้ ตัวแปร "ตัวนับ" `i` ถูกประกาศภายในลูปโดยตรง เรียกว่าการประกาศตัวแปรแบบ "อินไลน์" ตัวแปรแบบนี้จะมองเห็นได้เฉพาะภายในลูปเท่านั้น ```js run for (*!*let*/!* i = 0; i < 3; i++) { alert(i); // 0, 1, 2 } -alert(i); // error, no such variable +alert(i); // error, ไม่มีตัวแปรนี้ ``` -Instead of defining a variable, we could use an existing one: +แทนที่จะประกาศตัวแปรใหม่ เราสามารถใช้ตัวแปรที่มีอยู่แล้วก็ได้: ```js run let i = 0; -for (i = 0; i < 3; i++) { // use an existing variable +for (i = 0; i < 3; i++) { // ใช้ตัวแปรที่มีอยู่ alert(i); // 0, 1, 2 } -alert(i); // 3, visible, because declared outside of the loop +alert(i); // 3, มองเห็นได้ เพราะประกาศไว้นอกลูป ``` -```` +<<<<<<< HEAD -### Skipping parts +### การข้ามบางส่วน -Any part of `for` can be skipped. +ส่วนใดๆ ของ `for` ก็ข้ามได้ -For example, we can omit `begin` if we don't need to do anything at the loop start. +ตัวอย่างเช่น เราสามารถละส่วน `begin` ได้ถ้าไม่จำเป็นต้องทำอะไรตอนเริ่มลูป +======= +```` -Like here: +### Skipping parts +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +แบบนี้: ```js run -let i = 0; // we have i already declared and assigned +let i = 0; // เรามีการประกาศและกำหนดค่า i อยู่แล้ว -for (; i < 3; i++) { // no need for "begin" +for (; i < 3; i++) { // ไม่ต้องมีส่วน "begin" alert( i ); // 0, 1, 2 } ``` -We can also remove the `step` part: +เราสามารถเอาส่วน `step` ออกได้ด้วย: ```js run let i = 0; @@ -203,25 +224,25 @@ for (; i < 3;) { } ``` -This makes the loop identical to `while (i < 3)`. +ลูปแบบนี้จะเหมือนกับ `while (i < 3)` -We can actually remove everything, creating an infinite loop: +จริงๆ แล้วเราสามารถเอาทุกอย่างออกได้ เพื่อสร้างลูปไม่รู้จบ: ```js for (;;) { - // repeats without limits + // วนซ้ำไม่มีที่สิ้นสุด } ``` -Please note that the two `for` semicolons `;` must be present. Otherwise, there would be a syntax error. +โปรดสังเกตว่าจะต้องมีอัฒภาค `;` ทั้งสองตัวของ `for` อยู่เสมอ ไม่เช่นนั้นจะเกิด syntax error -## Breaking the loop +## การออกจากลูป -Normally, a loop exits when its condition becomes falsy. +โดยปกติแล้ว ลูปจะจบลงเมื่อเงื่อนไขเป็นเท็จ -But we can force the exit at any time using the special `break` directive. +แต่เราสามารถบังคับให้ออกจากลูปได้ทุกเมื่อด้วยการใช้คำสั่งพิเศษ `break` -For example, the loop below asks the user for a series of numbers, "breaking" when no number is entered: +ยกตัวอย่างเช่น ลูปด้านล่างจะถามผู้ใช้ให้ป้อนตัวเลขเป็นชุด และจะ "break" เมื่อไม่มีการป้อนตัวเลข: ```js run let sum = 0; @@ -240,32 +261,32 @@ while (true) { alert( 'Sum: ' + sum ); ``` -The `break` directive is activated at the line `(*)` if the user enters an empty line or cancels the input. It stops the loop immediately, passing control to the first line after the loop. Namely, `alert`. +คำสั่ง `break` จะทำงานที่บรรทัด `(*)` ถ้าผู้ใช้ป้อนบรรทัดว่างหรือกด cancel มันจะหยุดลูปทันที โดยส่งการควบคุมไปที่บรรทัดแรกหลังลูป นั่นคือไปที่ `alert` -The combination "infinite loop + `break` as needed" is great for situations when a loop's condition must be checked not in the beginning or end of the loop, but in the middle or even in several places of its body. +การใช้ "ลูปไม่รู้จบ + `break` เมื่อต้องการ" นั้นเหมาะมากสำหรับสถานการณ์ที่ต้องตรวจสอบเงื่อนไขของลูป ไม่ใช่ที่จุดเริ่มต้นหรือจุดสิ้นสุดของลูป แต่อยู่ตรงกลางหรือแม้กระทั่งหลายๆ จุดในตัวลูปเอง -## Continue to the next iteration [#continue] +## การข้ามไปยังรอบถัดไป [#continue] -The `continue` directive is a "lighter version" of `break`. It doesn't stop the whole loop. Instead, it stops the current iteration and forces the loop to start a new one (if the condition allows). +คำสั่ง `continue` เป็น "เวอร์ชันที่เบากว่า" ของ `break` มันไม่ได้หยุดลูปทั้งหมด แต่จะหยุดเฉพาะรอบปัจจุบันและบังคับให้ลูปเริ่มรอบใหม่แทน (ถ้าเงื่อนไขอนุญาต) -We can use it if we're done with the current iteration and would like to move on to the next one. +เราสามารถใช้มันได้ถ้าเราเสร็จสิ้นกับการประมวลผลในรอบปัจจุบันแล้วและต้องการข้ามไปยังรอบถัดไป -The loop below uses `continue` to output only odd values: +ลูปด้านล่างใช้ `continue` เพื่อแสดงผลเฉพาะค่าที่เป็นเลขคี่: ```js run no-beautify for (let i = 0; i < 10; i++) { - // if true, skip the remaining part of the body + // ถ้าเป็นจริง ข้ามส่วนที่เหลือของ body *!*if (i % 2 == 0) continue;*/!* - alert(i); // 1, then 3, 5, 7, 9 + alert(i); // 1, แล้วก็ 3, 5, 7, 9 } ``` -For even values of `i`, the `continue` directive stops executing the body and passes control to the next iteration of `for` (with the next number). So the `alert` is only called for odd values. +สำหรับค่า `i` ที่เป็นเลขคู่ คำสั่ง `continue` จะหยุดการประมวลผล body และส่งการควบคุมไปยังรอบถัดไปของ `for` (กับตัวเลขถัดไป) ดังนั้น `alert` จะถูกเรียกเฉพาะกับค่าที่เป็นเลขคี่เท่านั้น -````smart header="The `continue` directive helps decrease nesting" -A loop that shows odd values could look like this: +````smart header="คำสั่ง `continue` ช่วยลดความซับซ้อนของโค้ด" +ลูปที่แสดงค่าที่เป็นเลขคี่อาจเขียนได้แบบนี้: ```js run for (let i = 0; i < 10; i++) { @@ -277,15 +298,19 @@ for (let i = 0; i < 10; i++) { } ``` -From a technical point of view, this is identical to the example above. Surely, we can just wrap the code in an `if` block instead of using `continue`. +ในแง่เทคนิค โค้ดนี้เหมือนกับตัวอย่างด้านบนทุกประการ เราสามารถห่อโค้ดไว้ในบล็อก `if` แทนการใช้ `continue` ก็ได้ +<<<<<<< HEAD +แต่ผลข้างเคียงคือ มันจะสร้างระดับความซับซ้อนของโค้ดเพิ่มขึ้นอีกหนึ่งชั้น (การเรียก `alert` อยู่ภายในวงเล็บปีกกา) ถ้าโค้ดภายใน `if` ยาวกว่าสองสามบรรทัด มันอาจลดความสามารถในการอ่านโค้ดโดยรวมได้ +======= But as a side effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of `if` is longer than a few lines, that may decrease the overall readability. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```` -````warn header="No `break/continue` to the right side of '?'" -Please note that syntax constructs that are not expressions cannot be used with the ternary operator `?`. In particular, directives such as `break/continue` aren't allowed there. +````warn header="ไม่มี `break/continue` ที่ด้านขวาของ '?'" +โปรดสังเกตว่า โครงสร้างทางไวยากรณ์ที่ไม่ใช่นิพจน์ จะไม่สามารถใช้กับตัวดำเนินการแบบ 3 พารามิเตอร์ `?` ได้ โดยเฉพาะอย่างยิ่ง คำสั่งอย่างเช่น `break/continue` จะไม่ได้รับอนุญาตให้ใช้ในตำแหน่งนั้น -For example, if we take this code: +ตัวอย่างเช่น ถ้าเรามีโค้ดแบบนี้: ```js if (i > 5) { @@ -295,22 +320,26 @@ if (i > 5) { } ``` +<<<<<<< HEAD +...แล้วเขียนใหม่โดยใช้เครื่องหมายคำถาม: +======= ...and rewrite it using a question mark: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js no-beautify -(i > 5) ? alert(i) : *!*continue*/!*; // continue isn't allowed here +(i > 5) ? alert(i) : *!*continue*/!*; // continue ไม่ได้รับอนุญาตที่นี่ ``` -...it stops working: there's a syntax error. +...มันจะหยุดทำงาน: เกิด syntax error ขึ้น -This is just another reason not to use the question mark operator `?` instead of `if`. +นี่เป็นอีกเหตุผลหนึ่งที่ไม่ควรใช้ตัวดำเนินการแบบ 3 พารามิเตอร์ `?` แทน `if` ```` -## Labels for break/continue +## Labels สำหรับ break/continue -Sometimes we need to break out from multiple nested loops at once. +บางครั้งเราอาจต้องออกจากลูปที่ซ้อนกันหลายชั้นในคราวเดียว -For example, in the code below we loop over `i` and `j`, prompting for the coordinates `(i, j)` from `(0,0)` to `(2,2)`: +ตัวอย่างเช่น ในโค้ดด้านล่าง เราวนลูปด้วย `i` และ `j` เพื่อถามหาค่าที่พิกัด `(i, j)` ตั้งแต่ `(0,0)` ถึง `(2,2)`: ```js run no-beautify for (let i = 0; i < 3; i++) { @@ -319,26 +348,31 @@ for (let i = 0; i < 3; i++) { let input = prompt(`Value at coords (${i},${j})`, ''); - // what if we want to exit from here to Done (below)? + // จะทำอย่างไรถ้าเราต้องการออกจากที่นี่ไปสู่ Done (ด้านล่าง)? } } alert('Done!'); ``` -We need a way to stop the process if the user cancels the input. +เราต้องการวิธีหยุดกระบวนการนี้ถ้าผู้ใช้ยกเลิกการป้อนข้อมูล + +การใช้ `break` ธรรมดาหลังจาก `input` จะออกจากลูปชั้นในเท่านั้น ซึ่งยังไม่เพียงพอ -- labels จะมาช่วยได้! -The ordinary `break` after `input` would only break the inner loop. That's not sufficient -- labels, come to the rescue! +*label* คือตัวระบุที่มีเครื่องหมายโคลอนอยู่ข้างหน้าลูป: +<<<<<<< HEAD +======= A *label* is an identifier with a colon before a loop: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js labelName: for (...) { ... } ``` -The `break ` statement in the loop below breaks out to the label: +คำสั่ง `break ` ในลูปด้านล่างจะออกไปสู่ label: ```js run no-beautify *!*outer:*/!* for (let i = 0; i < 3; i++) { @@ -347,65 +381,74 @@ The `break ` statement in the loop below breaks out to the label: let input = prompt(`Value at coords (${i},${j})`, ''); - // if an empty string or canceled, then break out of both loops + // ถ้าเป็นสตริงว่างหรือกด cancel ให้ออกจากลูปทั้งสอง if (!input) *!*break outer*/!*; // (*) - // do something with the value... + // ทำอะไรบางอย่างกับค่าที่ได้... } } alert('Done!'); ``` -In the code above, `break outer` looks upwards for the label named `outer` and breaks out of that loop. +ในโค้ดด้านบน `break outer` จะมองหา label ชื่อ `outer` ขึ้นไป แล้วออกจากลูปนั้น -So the control goes straight from `(*)` to `alert('Done!')`. +ดังนั้นการควบคุมจะข้ามจาก `(*)` ไปสู่ `alert('Done!')` โดยตรง -We can also move the label onto a separate line: +เราสามารถย้าย label ไปอยู่บนบรรทัดแยกต่างหากได้ด้วย: ```js no-beautify outer: for (let i = 0; i < 3; i++) { ... } ``` -The `continue` directive can also be used with a label. In this case, code execution jumps to the next iteration of the labeled loop. +คำสั่ง `continue` ก็สามารถใช้ร่วมกับ label ได้เช่นกัน ในกรณีนี้ การประมวลผลโค้ดจะข้ามไปยังรอบถัดไปของลูปที่มี label กำกับ + +````warn header="Labels ไม่อนุญาตให้ \"กระโดด\" ไปที่ใดก็ได้" +Labels ไม่ได้อนุญาตให้เรากระโดดไปยังตำแหน่งใดๆ ก็ได้ในโค้ด -````warn header="Labels do not allow to \"jump\" anywhere" -Labels do not allow us to jump into an arbitrary place in the code. +ตัวอย่างเช่น เราไม่สามารถทำแบบนี้ได้: +<<<<<<< HEAD +======= For example, it is impossible to do this: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js -break label; // jump to the label below (doesn't work) +break label; // กระโดดไปสู่ label ด้านล่าง (ใช้ไม่ได้) label: for (...) ``` +<<<<<<< HEAD +คำสั่ง `break` ต้องอยู่ภายในบล็อกโค้ด ในทางเทคนิค บล็อกโค้ดใดๆ ที่มี label กำกับก็ใช้ได้ เช่น: +======= A `break` directive must be inside a code block. Technically, any labelled code block will do, e.g.: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js label: { // ... - break label; // works + break label; // ใช้ได้ // ... } ``` -...Although, 99.9% of the time `break` is used inside loops, as we've seen in the examples above. +...อย่างไรก็ตาม ในความเป็นจริง 99.9% ของเวลา `break` จะถูกใช้ภายในลูป เหมือนที่เราเห็นในตัวอย่างด้านบน -A `continue` is only possible from inside a loop. +ส่วน `continue` จะใช้ได้เฉพาะภายในลูปเท่านั้น ```` -## Summary +## สรุป -We covered 3 types of loops: +เราได้ครอบคลุมลูป 3 ประเภท: -- `while` -- The condition is checked before each iteration. -- `do..while` -- The condition is checked after each iteration. -- `for (;;)` -- The condition is checked before each iteration, additional settings available. +- `while` -- ตรวจสอบเงื่อนไขก่อนการวนลูปแต่ละรอบ +- `do..while` -- ตรวจสอบเงื่อนไขหลังการวนลูปแต่ละรอบ +- `for (;;)` -- ตรวจสอบเงื่อนไขก่อนการวนลูปแต่ละรอบ สามารถกำหนดค่าเริ่มต้นและปรับแต่งเพิ่มเติมได้ -To make an "infinite" loop, usually the `while(true)` construct is used. Such a loop, just like any other, can be stopped with the `break` directive. +ในการสร้างลูป "ไม่มีที่สิ้นสุด" มักจะใช้โครงสร้าง `while(true)` ลูปลักษณะนี้ เช่นเดียวกับลูปอื่นๆ สามารถหยุดได้ด้วยคำสั่ง `break` -If we don't want to do anything in the current iteration and would like to forward to the next one, we can use the `continue` directive. +หากเราไม่ต้องการทำอะไรในรอบปัจจุบัน และต้องการข้ามไปยังรอบถัดไป เราสามารถใช้คำสั่ง `continue` -`break/continue` support labels before the loop. A label is the only way for `break/continue` to escape a nested loop to go to an outer one. +`break/continue` รองรับการใช้ label ที่อยู่ข้างหน้าลูป label เป็นวิธีเดียวที่ `break/continue` จะสามารถออกจากลูปที่ซ้อนกันเพื่อไปยังลูปชั้นนอกได้ diff --git a/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md b/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md index d3e397434..91c1626c5 100644 --- a/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md +++ b/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md @@ -1,6 +1,6 @@ -To precisely match the functionality of `switch`, the `if` must use a strict comparison `'==='`. +เพื่อที่จะให้ตรงกับการทำงานของคำสั่ง `switch`, คำสั่ง `if` จึงต้องให้ `'==='` -For given strings though, a simple `'=='` works too. +ตามสตริงที่ให้มา `'=='` ก็ใช้ได้งานตามที่คาดหวังเช่นกัน ```js no-beautify if(browser == 'Edge') { @@ -15,6 +15,6 @@ if(browser == 'Edge') { } ``` -Please note: the construct `browser == 'Chrome' || browser == 'Firefox' …` is split into multiple lines for better readability. +โปรดทราบ: รูปประโยค `browser == 'Chrome' || browser == 'Firefox' …` ควรแบ่งเป็นหลายๆบรรทัดเพื่อให้อ่านง่ายขึ้น -But the `switch` construct is still cleaner and more descriptive. +แต่อย่างไรก็ตาม ในกรณีนี้คำสั่ง `switch` ก็ดูสะอาดและเข้าใจง่ายกว่า diff --git a/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md b/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md index f4dc0e5f1..20b050482 100644 --- a/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md +++ b/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Rewrite the "switch" into an "if" +# ลองมาแปลงคำสั่งจาก "switch" เป็น "if" -Write the code using `if..else` which would correspond to the following `switch`: +เขียนโค้ดโดยใช้ `if..else` โดยให้สอดคล้องกับ `switch` ด้านล่าง: ```js switch (browser) { diff --git a/1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md b/1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md index ed87dd94b..55fc36243 100644 --- a/1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md +++ b/1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md @@ -1,4 +1,4 @@ -The first two checks turn into two `case`. The third check is split into two cases: +ขั้นแรกมาเปลี่ยน if ตัวสองแรกเป็น `case` กันก่อน เพราะว่า if ตัวที่สามเราต้องใช้แยกออกมาเป็นสอง `case`: ```js run let a = +prompt('a?', ''); @@ -21,6 +21,6 @@ switch (a) { } ``` -Please note: the `break` at the bottom is not required. But we put it to make the code future-proof. +โปรดจำจงไว้: คำสั่ง `break` ที่บรรทัดล่างสุดไม่จำเป็นต้องใส่ก็ได้ แต่ทางเราเขียนไว้เผื่ออนาคต -In the future, there is a chance that we'd want to add one more `case`, for example `case 4`. And if we forget to add a break before it, at the end of `case 3`, there will be an error. So that's a kind of self-insurance. +เพราะว่าอนาคต มีโอกาสที่เราจะเพิ่ม `case` ขึ้นมาอีก ตัวอย่างเช่น `case 4` และเราลืมใส่คำสั่ง `break` ไว้ท้าย `case 3` ซึ่งจะทำให้เกิดผลลัพธ์ที่ไม่คาดหวัง ดังนั้นเพื่อรับประกันว่าโค้ดทุกอย่างยังคงทำงานอย่างถูกต้อง เราจึงใส่ไว้นั่นเอง diff --git a/1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md b/1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md index ec99d098d..697867b5b 100644 --- a/1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md +++ b/1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md @@ -2,9 +2,9 @@ importance: 4 --- -# Rewrite "if" into "switch" +# ลองมาแปลงคำสั่งจาก "if" เป็น "switch" -Rewrite the code below using a single `switch` statement: +ลองเขียนโค้ดด้านล่างใหม่โดยใช้คำสั่ง `switch` กัน: ```js run let a = +prompt('a?', ''); diff --git a/1-js/02-first-steps/14-switch/article.md b/1-js/02-first-steps/14-switch/article.md index d86babcec..7845b6bd3 100644 --- a/1-js/02-first-steps/14-switch/article.md +++ b/1-js/02-first-steps/14-switch/article.md @@ -1,22 +1,22 @@ -# The "switch" statement +# คำสั่ง "switch" -A `switch` statement can replace multiple `if` checks. +คำสั่ง `switch` สามารถใช้แทนการตรวจสอบด้วย `if` หลายๆ ครั้งได้ -It gives a more descriptive way to compare a value with multiple variants. +มันให้วิธีเปรียบเทียบค่ากับตัวเลือกหลายๆ ตัวอย่างเข้าใจง่ายกว่า -## The syntax +## ไวยากรณ์ -The `switch` has one or more `case` blocks and an optional default. +`switch` จะมีหนึ่งหรือหลายบล็อก `case` และมี `default` เป็นตัวเลือกเสริม -It looks like this: +มีรูปแบบดังนี้: ```js no-beautify switch(x) { - case 'value1': // if (x === 'value1') + case 'value1': // ถ้า (x === 'value1') ... [break] - case 'value2': // if (x === 'value2') + case 'value2': // ถ้า (x === 'value2') ... [break] @@ -26,71 +26,71 @@ switch(x) { } ``` -- The value of `x` is checked for a strict equality to the value from the first `case` (that is, `value1`) then to the second (`value2`) and so on. -- If the equality is found, `switch` starts to execute the code starting from the corresponding `case`, until the nearest `break` (or until the end of `switch`). -- If no case is matched then the `default` code is executed (if it exists). +- ค่าของ `x` จะถูกตรวจสอบความเท่าเทียมกันอย่างเข้มงวดกับค่าจาก `case` แรก (คือ `value1`) จากนั้นเป็น `case` ที่สอง (`value2`) และต่อไปเรื่อยๆ +- ถ้าพบความเท่ากัน `switch` จะเริ่มรันโค้ดจาก `case` ที่ตรงกัน จนกว่าจะเจอ `break` ที่ใกล้ที่สุด (หรือจนจบ `switch`) +- ถ้าไม่ตรงกับ `case` ใด โค้ดใน `default` จะถูกรัน (ถ้ามี) -## An example +## ตัวอย่าง -An example of `switch` (the executed code is highlighted): +ตัวอย่างของ `switch` (โค้ดที่ถูกรันจะเน้นให้เห็น): ```js run let a = 2 + 2; switch (a) { case 3: - alert( 'Too small' ); + alert( 'เล็กไป' ); break; *!* case 4: - alert( 'Exactly!' ); + alert( 'ถูกต้อง!' ); break; */!* case 5: - alert( 'Too big' ); + alert( 'ใหญ่ไป' ); break; default: - alert( "I don't know such values" ); + alert( "ไม่รู้จักค่านี้" ); } ``` -Here the `switch` starts to compare `a` from the first `case` variant that is `3`. The match fails. +ที่นี่ `switch` จะเริ่มเปรียบเทียบ `a` กับ `case` แรกคือ `3` ซึ่งไม่ตรงกัน -Then `4`. That's a match, so the execution starts from `case 4` until the nearest `break`. +จากนั้นเป็น `4` ซึ่งตรงกัน ดังนั้นโค้ดจะเริ่มรันจาก `case 4` จนกว่าจะเจอ `break` -**If there is no `break` then the execution continues with the next `case` without any checks.** +**ถ้าไม่มี `break` โค้ดจะรันต่อไปยัง `case` ถัดไปเลยโดยไม่ตรวจสอบอะไร** -An example without `break`: +ตัวอย่างที่ไม่มี `break`: ```js run let a = 2 + 2; switch (a) { case 3: - alert( 'Too small' ); + alert( 'เล็กไป' ); *!* case 4: - alert( 'Exactly!' ); + alert( 'ถูกต้อง!' ); case 5: - alert( 'Too big' ); - default: - alert( "I don't know such values" ); + alert( 'ใหญ่ไป' ); + default: + alert( "ไม่รู้จักค่านี้" ); */!* } ``` -In the example above we'll see sequential execution of three `alert`s: +ในตัวอย่างข้างบน จะเห็น `alert` สามอันทำงานต่อเนื่องกัน: ```js -alert( 'Exactly!' ); -alert( 'Too big' ); -alert( "I don't know such values" ); +alert( 'ถูกต้อง!' ); +alert( 'ใหญ่ไป' ); +alert( "ไม่รู้จักค่านี้" ); ``` -````smart header="Any expression can be a `switch/case` argument" -Both `switch` and `case` allow arbitrary expressions. +````smart header="นิพจน์อะไรก็ใช้เป็นอาร์กิวเมนต์ของ `switch/case` ได้" +ทั้ง `switch` และ `case` สามารถใช้นิพจน์อะไรก็ได้ -For example: +เช่น: ```js run let a = "1"; @@ -99,74 +99,78 @@ let b = 0; switch (+a) { *!* case b + 1: - alert("this runs, because +a is 1, exactly equals b+1"); + alert("นี่ทำงาน เพราะ +a เป็น 1 ซึ่งเท่ากับ b+1"); break; */!* default: - alert("this doesn't run"); + alert("นี่ไม่ทำงาน"); } ``` -Here `+a` gives `1`, that's compared with `b + 1` in `case`, and the corresponding code is executed. +ที่นี่ `+a` ให้ค่า `1` ซึ่งจะถูกเปรียบเทียบกับ `b + 1` ใน `case` และโค้ดที่สอดคล้องจะถูกรัน ```` -## Grouping of "case" +## การจัดกลุ่ม "case" -Several variants of `case` which share the same code can be grouped. +`case` หลายๆ แบบที่รันโค้ดเดียวกัน สามารถจัดกลุ่มรวมกันได้ -For example, if we want the same code to run for `case 3` and `case 5`: +ตัวอย่างเช่น ถ้าเราต้องการให้โค้ดเดียวกันทำงานทั้งใน `case 3` และ `case 5`: ```js run no-beautify let a = 3; switch (a) { case 4: - alert('Right!'); + alert('ถูกต้อง!'); break; *!* - case 3: // (*) grouped two cases + case 3: // (*) จัดกลุ่มสอง case ไว้ด้วยกัน case 5: - alert('Wrong!'); - alert("Why don't you take a math class?"); + alert('ผิด!'); + alert("ลองไปเรียนคณิตหน่อยไหม"); break; */!* default: - alert('The result is strange. Really.'); + alert('ผลลัพธ์แปลกมากเลย'); } ``` -Now both `3` and `5` show the same message. +ตอนนี้ทั้ง `3` และ `5` จะแสดงข้อความเดียวกัน +<<<<<<< HEAD +ความสามารถในการ "จัดกลุ่ม" `case` เป็นผลข้างเคียงของวิธีการทำงานของ `switch/case` เมื่อไม่มี `break` ในที่นี้ `case 3` จะเริ่มรันโค้ดจากบรรทัด `(*)` และรันผ่าน `case 5` ไปเลย เพราะไม่มี `break` +======= The ability to "group" cases is a side effect of how `switch/case` works without `break`. Here the execution of `case 3` starts from the line `(*)` and goes through `case 5`, because there's no `break`. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -## Type matters +## ชนิดข้อมูลมีความสำคัญ -Let's emphasize that the equality check is always strict. The values must be of the same type to match. +ขอเน้นว่าการตรวจสอบความเท่ากันจะเป็นแบบเข้มงวดเสมอ ค่าต้องเป็นชนิดเดียวกันจึงจะตรงกัน -For example, let's consider the code: +ตัวอย่างเช่น ลองพิจารณาโค้ดนี้: ```js run -let arg = prompt("Enter a value?"); +let arg = prompt("ใส่ค่ามา"); switch (arg) { case '0': case '1': - alert( 'One or zero' ); + alert( 'ศูนย์หรือหนึ่ง' ); break; case '2': - alert( 'Two' ); + alert( 'สอง' ); break; case 3: - alert( 'Never executes!' ); + alert( 'จะไม่มีทางรันเลย!' ); break; default: - alert( 'An unknown value' ); + alert( 'ค่าที่ไม่รู้จัก' ); } ``` -1. For `0`, `1`, the first `alert` runs. -2. For `2` the second `alert` runs. -3. But for `3`, the result of the `prompt` is a string `"3"`, which is not strictly equal `===` to the number `3`. So we've got a dead code in `case 3`! The `default` variant will execute. +1. สำหรับ `0`, `1` จะแสดง `alert` แรก +2. สำหรับ `2` จะแสดง `alert` ที่สอง +3. แต่สำหรับ `3` ผลลัพธ์จาก `prompt` จะเป็น string `"3"` ซึ่งไม่เท่ากันอย่างเข้มงวด `===` กับตัวเลข `3` ดังนั้นเราจะมีโค้ดที่ไม่มีทางรันได้ใน `case 3`! แต่ `default` จะถูกรันแทน \ No newline at end of file diff --git a/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md index e3a0df77c..2a6efeddc 100644 --- a/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md +++ b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md @@ -1,3 +1,7 @@ +<<<<<<< HEAD +ไม่มีความแตกต่าง +======= No difference! -In both cases, `return confirm('Did parents allow you?')` executes exactly when the `if` condition is falsy. \ No newline at end of file +In both cases, `return confirm('Did parents allow you?')` executes exactly when the `if` condition is falsy. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 diff --git a/1-js/02-first-steps/15-function-basics/1-if-else-required/task.md b/1-js/02-first-steps/15-function-basics/1-if-else-required/task.md index 4f69a5c8c..0ba7985e2 100644 --- a/1-js/02-first-steps/15-function-basics/1-if-else-required/task.md +++ b/1-js/02-first-steps/15-function-basics/1-if-else-required/task.md @@ -2,11 +2,11 @@ importance: 4 --- -# Is "else" required? +# จำเป็นต้องมี "else" หรือไม่? -The following function returns `true` if the parameter `age` is greater than `18`. +ฟังก์ชั่นด้านล่างจะส่งคืนค่า `true` หากพารามิเตอร์์ `age` มีค่ามากกว่า `18` -Otherwise it asks for a confirmation and returns its result: +มิเช่นนั้น ฟังก์ชั่น `confirm` จะทำงานแล้ว ส่งคืนผลลัพธ์ที่ผู้ใช้กรอกมา ```js function checkAge(age) { @@ -21,7 +21,7 @@ function checkAge(age) { } ``` -Will the function work differently if `else` is removed? +ฟังก์ชั่นจะทำงานต่างออกไปหรือไม่หากไม่มี `else` ```js function checkAge(age) { @@ -35,4 +35,4 @@ function checkAge(age) { } ``` -Is there any difference in the behavior of these two variants? +อะไรคือความต่างกันของทั้งสองตัว 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 415fed3e0..038472fcf 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -1,64 +1,68 @@ -# Functions +# ฟังก์ชัน -Quite often we need to perform a similar action in many places of the script. +บ่อยครั้งที่เราต้องทำการกระทำที่คล้ายๆ กันในหลายๆ ที่ของสคริปต์ -For example, we need to show a nice-looking message when a visitor logs in, logs out and maybe somewhere else. +เช่น เราอาจต้องแสดงข้อความที่ดูดีเมื่อผู้ใช้ล็อกอิน ล็อกเอาท์ หรือที่อื่นๆ -Functions are the main "building blocks" of the program. They allow the code to be called many times without repetition. +ฟังก์ชันคือ "บล็อกสร้าง" หลักของโปรแกรม มันทำให้เราเรียกใช้โค้ดได้หลายครั้งโดยไม่ต้องเขียนซ้ำ -We've already seen examples of built-in functions, like `alert(message)`, `prompt(message, default)` and `confirm(question)`. But we can create functions of our own as well. +เราเคยเห็นตัวอย่างฟังก์ชันที่มีมาในตัวแล้ว เช่น `alert(message)`, `prompt(message, default)` และ `confirm(question)` แต่เราก็สามารถสร้างฟังก์ชันของตัวเองได้ด้วย -## Function Declaration +## การประกาศฟังก์ชัน -To create a function we can use a *function declaration*. +ในการสร้างฟังก์ชัน เราสามารถใช้ *การประกาศฟังก์ชัน* -It looks like this: +ซึ่งมีรูปแบบดังนี้: ```js function showMessage() { - alert( 'Hello everyone!' ); + alert( 'สวัสดีทุกคน!' ); } ``` -The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (comma-separated, empty in the example above, we'll see examples later) and finally the code of the function, also named "the function body", between curly braces. +ใช้คีย์เวิร์ด `function` ก่อน ตามด้วย*ชื่อฟังก์ชัน* แล้วก็รายการ *parameter* ในวงเล็บ (คั่นด้วยเครื่องหมายจุลภาค ในตัวอย่างข้างบนจะเว้นว่าง เดี๋ยวจะมีตัวอย่างอีกทีหลัง) สุดท้ายคือโค้ดของฟังก์ชันระหว่างปีกกาปิดเปิด ที่เรียกว่า "ตัวฟังก์ชัน" หรือ "function body" ```js function name(parameter1, parameter2, ... parameterN) { +<<<<<<< HEAD + // ตัวฟังก์ชัน +======= // body +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 } ``` -Our new function can be called by its name: `showMessage()`. +ฟังก์ชันใหม่ของเราสามารถเรียกใช้ได้ด้วยชื่อของมัน เช่น: `showMessage()` -For instance: +ดังตัวอย่าง: ```js run function showMessage() { - alert( 'Hello everyone!' ); + alert( 'สวัสดีทุกคน!' ); } *!* showMessage(); showMessage(); -*/!* +*/!* ``` -The call `showMessage()` executes the code of the function. Here we will see the message two times. +เมื่อเรียก `showMessage()` ก็จะรันโค้ดในตัวฟังก์ชัน ในที่นี้เราจะเห็นข้อความถูกแสดงสองครั้ง -This example clearly demonstrates one of the main purposes of functions: to avoid code duplication. +ตัวอย่างนี้แสดงให้เห็นวัตถุประสงค์หลักอย่างหนึ่งของฟังก์ชัน นั่นคือเพื่อหลีกเลี่ยงการเขียนโค้ดซ้ำ -If we ever need to change the message or the way it is shown, it's enough to modify the code in one place: the function which outputs it. +ถ้าเราต้องการเปลี่ยนข้อความหรือวิธีแสดงผล ก็แค่แก้ไขโค้ดในที่เดียว นั่นคือในตัวฟังก์ชันที่ทำการแสดงผลมัน -## Local variables +## ตัวแปรภายในฟังก์ชัน (Local variables) -A variable declared inside a function is only visible inside that function. +ตัวแปรที่ประกาศภายในฟังก์ชัน จะมองเห็นได้เฉพาะภายในฟังก์ชันนั้นเท่านั้น -For example: +ตัวอย่างเช่น: ```js run function showMessage() { *!* - let message = "Hello, I'm JavaScript!"; // local variable + let message = "Hello, I'm JavaScript!"; // ตัวแปรภายในฟังก์ชัน */!* alert( message ); @@ -66,12 +70,12 @@ function showMessage() { showMessage(); // Hello, I'm JavaScript! -alert( message ); // <-- Error! The variable is local to the function +alert( message ); // <-- Error! ตัวแปรอยู่ภายในฟังก์ชัน ไม่สามารถเข้าถึงจากภายนอกได้ ``` -## Outer variables +## ตัวแปรภายนอก (Outer variables) -A function can access an outer variable as well, for example: +ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้ด้วย เช่น: ```js run no-beautify let *!*userName*/!* = 'John'; @@ -84,65 +88,65 @@ function showMessage() { showMessage(); // Hello, John ``` -The function has full access to the outer variable. It can modify it as well. +ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้อย่างเต็มที่ และยังสามารถแก้ไขค่าได้ด้วย -For instance: +ตัวอย่างเช่น: ```js run let *!*userName*/!* = 'John'; function showMessage() { - *!*userName*/!* = "Bob"; // (1) changed the outer variable + *!*userName*/!* = "Bob"; // (1) เปลี่ยนค่าตัวแปรภายนอก let message = 'Hello, ' + *!*userName*/!*; alert(message); } -alert( userName ); // *!*John*/!* before the function call +alert( userName ); // *!*John*/!* ก่อนเรียกฟังก์ชัน showMessage(); -alert( userName ); // *!*Bob*/!*, the value was modified by the function +alert( userName ); // *!*Bob*/!*, ค่าถูกเปลี่ยนโดยฟังก์ชัน ``` -The outer variable is only used if there's no local one. +ตัวแปรภายนอกจะถูกใช้ก็ต่อเมื่อไม่มีตัวแปรภายในฟังก์ชั่นที่ชื่อเดียวกัน -If a same-named variable is declared inside the function then it *shadows* the outer one. For instance, in the code below the function uses the local `userName`. The outer one is ignored: +ถ้ามีการประกาศตัวแปรที่ชื่อซ้ำกันภายในฟังก์ชัน มันจะ *บดบัง* ตัวแปรภายนอก เช่น ในโค้ดด้านล่าง ฟังก์ชันจะใช้ `userName` ภายในของตัวเอง ส่วนตัวภายนอกจะถูกมองข้าม: ```js run let userName = 'John'; function showMessage() { *!* - let userName = "Bob"; // declare a local variable + let userName = "Bob"; // ประกาศตัวแปรภายในฟังก์ชัน */!* let message = 'Hello, ' + userName; // *!*Bob*/!* alert(message); } -// the function will create and use its own userName +// ฟังก์ชันจะสร้างและใช้ userName ของตัวเอง showMessage(); -alert( userName ); // *!*John*/!*, unchanged, the function did not access the outer variable +alert( userName ); // *!*John*/!*, ไม่เปลี่ยนแปลง เพราะฟังก์ชันไม่ได้เข้าถึงตัวแปรภายนอก ``` -```smart header="Global variables" -Variables declared outside of any function, such as the outer `userName` in the code above, are called *global*. +```smart header="ตัวแปรโกลบอล (Global variables)" +ตัวแปรที่ประกาศนอกฟังก์ชันใดๆ เช่น `userName` ภายนอกในตัวอย่างข้างต้น เรียกว่า *ตัวแปรโกลบอล* -Global variables are visible from any function (unless shadowed by locals). +ตัวแปรโกลบอลจะมองเห็นได้จากทุกฟังก์ชัน (ยกเว้นถูกบดบังโดยตัวแปรภายในฟังก์ชั่น) -It's a good practice to minimize the use of global variables. Modern code has few or no globals. Most variables reside in their functions. Sometimes though, they can be useful to store project-level data. +เป็นแนวทางปฏิบัติที่ดีที่จะลดการใช้ตัวแปรโกลบอล โค้ดสมัยใหม่มักมีตัวแปรโกลบอลน้อยมากหรือไม่มีเลย ตัวแปรส่วนใหญ่จะอยู่ภายในฟังก์ชันของตัวเอง อย่างไรก็ตาม บางครั้งตัวแปรโกลบอลก็มีประโยชน์ในการเก็บข้อมูลระดับโปรเจกต์ ``` -## Parameters +## พารามิเตอร์ (Parameters) -We can pass arbitrary data to functions using parameters. +เราสามารถส่งผ่านข้อมูลใดๆ ไปยังฟังก์ชันโดยใช้พารามิเตอร์ได้ -In the example below, the function has two parameters: `from` and `text`. +ในตัวอย่างด้านล่าง ฟังก์ชันมีพารามิเตอร์สองตัวคือ `from` และ `text` ```js run -function showMessage(*!*from, text*/!*) { // parameters: from, text +function showMessage(*!*from, text*/!*) { // พารามิเตอร์: from, text alert(from + ': ' + text); } @@ -150,15 +154,15 @@ function showMessage(*!*from, text*/!*) { // parameters: from, text *!*showMessage('Ann', "What's up?");*/!* // Ann: What's up? (**) ``` -When the function is called in lines `(*)` and `(**)`, the given values are copied to local variables `from` and `text`. Then the function uses them. +เมื่อฟังก์ชันถูกเรียกในบรรทัด `(*)` และ `(**)` ค่าที่ส่งเข้าไปจะถูกคัดลอกไปยังตัวแปรภายในฟังก์ชั่น `from` และ `text` จากนั้นฟังก์ชันก็จะใช้ตัวแปรเหล่านั้น -Here's one more example: we have a variable `from` and pass it to the function. Please note: the function changes `from`, but the change is not seen outside, because a function always gets a copy of the value: +นี่คืออีกตัวอย่าง: เรามีตัวแปร `from` และส่งผ่านมันเข้าไปในฟังก์ชัน สังเกตว่า ฟังก์ชันเปลี่ยนค่า `from` แต่การเปลี่ยนแปลงนั้นจะไม่ปรากฏภายนอก เพราะฟังก์ชันจะได้รับสำเนาของค่าเสมอ: ```js run function showMessage(from, text) { *!* - from = '*' + from + '*'; // make "from" look nicer + from = '*' + from + '*'; // ทำให้ "from" ดูสวยงามขึ้น */!* alert( from + ': ' + text ); @@ -168,35 +172,39 @@ let from = "Ann"; showMessage(from, "Hello"); // *Ann*: Hello -// the value of "from" is the same, the function modified a local copy -alert( from ); // Ann +// ค่าของ "from" ยังเหมือนเดิม ฟังก์ชันแก้ไขสำเนาในตัวเอง +alert( from ); // Ann ``` -When a value is passed as a function parameter, it's also called an *argument*. +เมื่อค่าถูกส่งผ่านเข้าไปเป็นพารามิเตอร์ของฟังก์ชัน เราเรียกค่านั้นว่า *อาร์กิวเมนต์ (argument)* -In other words, to put these terms straight: +หรือพูดอีกอย่างคือ เพื่อให้เข้าใจคำศัพท์ชัดเจน: +<<<<<<< HEAD +- พารามิเตอร์ คือตัวแปรที่ระบุในวงเล็บตอนประกาศฟังก์ชัน (เป็นคำศัพท์ช่วงประกาศ) +- อาร์กิวเมนต์ คือค่าที่ส่งผ่านเข้าไปในฟังก์ชันตอนเรียกใช้ (เป็นคำศัพท์ช่วงเรียกใช้) +======= - A parameter is the variable listed inside the parentheses in the function declaration (it's a declaration time term). - An argument is the value that is passed to the function when it is called (it's a call time term). +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -We declare functions listing their parameters, then call them passing arguments. - -In the example above, one might say: "the function `showMessage` is declared with two parameters, then called with two arguments: `from` and `"Hello"`". +เราประกาศฟังก์ชันโดยระบุพารามิเตอร์ของมัน จากนั้นเรียกใช้มันโดยส่งผ่านอาร์กิวเมนต์เข้าไป +ในตัวอย่างข้างบน เราอาจพูดว่า: "ฟังก์ชัน `showMessage` ถูกประกาศด้วยพารามิเตอร์สองตัว จากนั้นถูกเรียกใช้ด้วยอาร์กิวเมนต์สองตัวคือ `from` และ `"Hello"`" -## Default values +## ค่าเริ่มต้น (Default values) -If a function is called, but an argument is not provided, then the corresponding value becomes `undefined`. +หากฟังก์ชันถูกเรียกใช้แต่ไม่ได้ส่งอาร์กิวเมนต์มาด้วย ค่าที่สอดคล้องกันจะเป็น `undefined` -For instance, the aforementioned function `showMessage(from, text)` can be called with a single argument: +ยกตัวอย่างเช่น ฟังก์ชัน `showMessage(from, text)` ที่กล่าวถึงก่อนหน้า สามารถเรียกใช้ด้วยอาร์กิวเมนต์เพียงตัวเดียวได้: ```js showMessage("Ann"); ``` -That's not an error. Such a call would output `"*Ann*: undefined"`. As the value for `text` isn't passed, it becomes `undefined`. +นี่ไม่ใช่ข้อผิดพลาด การเรียกแบบนี้จะแสดงผลเป็น `"*Ann*: undefined"` เนื่องจากไม่ได้ส่งค่าให้กับพารามิเตอร์ `text` จึงมีค่าเป็น `undefined` -We can specify the so-called "default" (to use if omitted) value for a parameter in the function declaration, using `=`: +เราสามารถระบุค่าที่เรียกว่า "ค่าเริ่มต้น" (ใช้เมื่อไม่ได้ส่งค่ามา) สำหรับพารามิเตอร์ในการประกาศฟังก์ชันได้ โดยใช้ `=`: ```js run function showMessage(from, *!*text = "no text given"*/!*) { @@ -206,6 +214,9 @@ function showMessage(from, *!*text = "no text given"*/!*) { showMessage("Ann"); // Ann: no text given ``` +<<<<<<< HEAD +ตอนนี้ถ้าไม่ได้ส่งพารามิเตอร์ `text` มา มันจะมีค่าเป็น `"no text given"` +======= Now if the `text` parameter is not passed, it will get the value `"no text given"`. The default value also jumps in if the parameter exists, but strictly equals `undefined`, like this: @@ -213,24 +224,37 @@ The default value also jumps in if the parameter exists, but strictly equals `un ```js showMessage("Ann", undefined); // Ann: no text given ``` +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Here `"no text given"` is a string, but it can be a more complex expression, which is only evaluated and assigned if the parameter is missing. So, this is also possible: +ค่าเริ่มต้นจะถูกนำมาใช้ด้วย ถ้าพารามิเตอร์มีอยู่แต่ค่าเป็น `undefined` อย่างเคร่งครัด เช่นนี้: + +```js +showMessage("Ann", undefined); // Ann: no text given +``` + +ในที่นี้ `"no text given"` เป็น string แต่มันสามารถเป็นนิพจน์ที่ซับซ้อนกว่านั้นได้ ซึ่งจะถูกประเมินค่าและกำหนดให้เฉพาะเมื่อไม่ได้ส่งพารามิเตอร์มาเท่านั้น ดังนั้นสิ่งนี้ก็เป็นไปได้: ```js run function showMessage(from, text = anotherFunction()) { - // anotherFunction() only executed if no text given - // its result becomes the value of text + // anotherFunction() จะถูกเรียกใช้เฉพาะเมื่อไม่ได้ส่ง text มา + // ผลลัพธ์ของมันจะกลายเป็นค่าของ text } ``` -```smart header="Evaluation of default parameters" -In JavaScript, a default parameter is evaluated every time the function is called without the respective parameter. +```smart header="การประเมินค่าพารามิเตอร์เริ่มต้น" +ใน JavaScript พารามิเตอร์เริ่มต้นจะถูกประเมินค่าทุกครั้งที่เรียกใช้ฟังก์ชันโดยไม่ส่งพารามิเตอร์ที่เกี่ยวข้อง -In the example above, `anotherFunction()` isn't called at all, if the `text` parameter is provided. +ในตัวอย่างข้างต้น `anotherFunction()` จะไม่ถูกเรียกใช้เลย ถ้าส่งพารามิเตอร์ `text` มา -On the other hand, it's independently called every time when `text` is missing. +ในทางกลับกัน มันจะถูกเรียกใช้แยกต่างหากทุกครั้งที่ไม่ได้ส่ง `text` มา ``` +<<<<<<< HEAD +````smart header="พารามิเตอร์เริ่มต้นในโค้ด JavaScript เก่า" +เมื่อหลายปีก่อน JavaScript ไม่รองรับไวยากรณ์ของพารามิเตอร์เริ่มต้น ดังนั้นคนจึงใช้วิธีอื่นในการระบุค่าเริ่มต้น + +ปัจจุบันเราอาจพบเจอสิ่งเหล่านี้ในสคริปต์เก่าๆ +======= ````smart header="Default parameters in old JavaScript code" Several years ago, JavaScript didn't support the syntax for default parameters. So people used other ways to specify them. @@ -266,53 +290,84 @@ function showMessage(from, text) { ### Alternative default parameters Sometimes it makes sense to assign default values for parameters at a later stage after the function declaration. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +เช่น การตรวจสอบ `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'; + ... +} +``` +```` + +### พารามิเตอร์เริ่มต้นทางเลือก -We can check if the parameter is passed during the function execution, by comparing it with `undefined`: +บางครั้งการกำหนดค่าเริ่มต้นให้พารามิเตอร์ในภายหลัง หลังจากประกาศฟังก์ชันไปแล้ว ก็มีเหตุผลเช่นกัน + +เราสามารถตรวจสอบว่ามีการส่งพารามิเตอร์มาหรือไม่ระหว่างการทำงานของฟังก์ชัน โดยเปรียบเทียบกับ `undefined`: ```js run function showMessage(text) { // ... *!* - if (text === undefined) { // if the parameter is missing - text = 'empty message'; + if (text === undefined) { // ถ้าไม่มีพารามิเตอร์ส่งมา + text = 'ข้อความว่าง'; } */!* alert(text); } -showMessage(); // empty message +showMessage(); // ข้อความว่าง ``` -...Or we could use the `||` operator: +...หรือเราสามารถใช้ตัวดำเนินการ `||`: ```js function showMessage(text) { - // if text is undefined or otherwise falsy, set it to 'empty' + // ถ้า text เป็น undefined หรือ falsy อื่นๆ ให้กำหนดเป็น 'empty' text = text || 'empty'; - ... + ... } ``` -Modern JavaScript engines support the [nullish coalescing operator](info:nullish-coalescing-operator) `??`, it's better when most falsy values, such as `0`, should be considered "normal": +JavaScript เอนจินสมัยใหม่รองรับ[ตัวดำเนินการรวม nullish](info:nullish-coalescing-operator) `??` ซึ่งจะเหมาะกว่าเมื่อต้องการให้ค่า falsy ส่วนใหญ่ เช่น `0` ถือเป็นค่า "ปกติ": ```js run function showCount(count) { - // if count is undefined or null, show "unknown" + // ถ้า count เป็น undefined หรือ null ให้แสดง "unknown" alert(count ?? "unknown"); } showCount(0); // 0 -showCount(null); // unknown +showCount(null); // unknown showCount(); // unknown ``` -## Returning a value +## การส่งคืนค่า (Returning a value) -A function can return a value back into the calling code as the result. +ฟังก์ชันสามารถส่งคืนค่ากลับไปยังโค้ดที่เรียกใช้เป็นผลลัพธ์ได้ -The simplest example would be a function that sums two values: +ตัวอย่างง่ายๆ คือฟังก์ชันที่รวมผลบวกของสองค่า: ```js run no-beautify function sum(a, b) { @@ -323,9 +378,9 @@ let result = sum(1, 2); alert( result ); // 3 ``` -The directive `return` can be in any place of the function. When the execution reaches it, the function stops, and the value is returned to the calling code (assigned to `result` above). +คำสั่ง `return` สามารถอยู่ที่ไหนก็ได้ในฟังก์ชัน เมื่อการทำงานมาถึงมัน ฟังก์ชันจะหยุดและส่งคืนค่าไปยังโค้ดที่เรียกใช้ (กำหนดให้กับ `result` ในตัวอย่างข้างต้น) -There may be many occurrences of `return` in a single function. For instance: +ในฟังก์ชันเดียวอาจมีหลายจุดที่ใช้ `return` ได้ เช่น: ```js run function checkAge(age) { @@ -335,23 +390,23 @@ function checkAge(age) { */!* } else { *!* - return confirm('Do you have permission from your parents?'); + return confirm('คุณได้รับอนุญาตจากผู้ปกครองหรือไม่?'); */!* } } -let age = prompt('How old are you?', 18); +let age = prompt('คุณอายุเท่าไหร่?', 18); if ( checkAge(age) ) { - alert( 'Access granted' ); + alert('อนุญาตให้เข้าใช้งาน'); } else { - alert( 'Access denied' ); + alert('ไม่อนุญาตให้เข้าใช้งาน'); } ``` -It is possible to use `return` without a value. That causes the function to exit immediately. +เราสามารถใช้ `return` โดยไม่มีค่าก็ได้ ซึ่งจะทำให้ฟังก์ชันจบการทำงานทันที -For example: +ตัวอย่างเช่น: ```js function showMovie(age) { @@ -361,25 +416,25 @@ function showMovie(age) { */!* } - alert( "Showing you the movie" ); // (*) + alert("กำลังแสดงภาพยนตร์ให้ชม"); // (*) // ... } ``` -In the code above, if `checkAge(age)` returns `false`, then `showMovie` won't proceed to the `alert`. +ในโค้ดข้างต้น ถ้า `checkAge(age)` คืนค่า `false` ฟังก์ชัน `showMovie` จะไม่ทำงานต่อไปที่ `alert` -````smart header="A function with an empty `return` or without it returns `undefined`" -If a function does not return a value, it is the same as if it returns `undefined`: +````smart header="ฟังก์ชันที่มี `return` ว่างหรือไม่มี `return` จะคืนค่า `undefined`" +ถ้าฟังก์ชันไม่มีการคืนค่า มันจะเหมือนกับการคืนค่า `undefined`: ```js run -function doNothing() { /* empty */ } +function doNothing() { /* ว่าง */ } alert( doNothing() === undefined ); // true ``` -An empty `return` is also the same as `return undefined`: +`return` ว่างก็เหมือนกับ `return undefined`: -```js run +```js run function doNothing() { return; } @@ -388,23 +443,23 @@ alert( doNothing() === undefined ); // true ``` ```` -````warn header="Never add a newline between `return` and the value" -For a long expression in `return`, it might be tempting to put it on a separate line, like this: +````warn header="อย่าขึ้นบรรทัดใหม่ระหว่าง `return` กับค่าที่คืน" +สำหรับนิพจน์ยาวๆ ใน `return` อาจเย้ายวนใจให้แยกเป็นบรรทัดใหม่ แบบนี้: ```js return (some + long + expression + or + whatever * f(a) + f(b)) ``` -That doesn't work, because JavaScript assumes a semicolon after `return`. That'll work the same as: +นั่นจะไม่ทำงาน เพราะ JavaScript จะสันนิษฐานว่ามีเครื่องหมายอัฒภาคหลัง `return` ซึ่งจะทำงานเหมือนกับ: -```js +```js return*!*;*/!* (some + long + expression + or + whatever * f(a) + f(b)) ``` -So, it effectively becomes an empty return. +ดังนั้นมันจะกลายเป็น return เปล่าๆ อย่างมีประสิทธิภาพ -If we want the returned expression to wrap across multiple lines, we should start it at the same line as `return`. Or at least put the opening parentheses there as follows: +ถ้าเราต้องการให้นิพจน์ที่คืนค่าขึ้นบรรทัดใหม่ เราควรเริ่มต้นในบรรทัดเดียวกับ `return` หรืออย่างน้อยควรใส่วงเล็บเปิดเอาไว้ที่นั่น แบบนี้: ```js return ( @@ -413,67 +468,72 @@ return ( whatever * f(a) + f(b) ) ``` -And it will work just as we expect it to. + +และมันจะทำงานตามที่เราคาดหวัง ```` -## Naming a function [#function-naming] +## การตั้งชื่อฟังก์ชัน [#function-naming] -Functions are actions. So their name is usually a verb. It should be brief, as accurate as possible and describe what the function does, so that someone reading the code gets an indication of what the function does. +ฟังก์ชันคือการกระทำ ดังนั้นชื่อของมันมักจะเป็นคำกริยา ชื่อควรสั้นกระชับ ตรงประเด็นที่สุดเท่าที่จะเป็นไปได้ และบ่งบอกว่าฟังก์ชันทำอะไร เพื่อให้คนที่อ่านโค้ดเข้าใจได้ทันทีว่าฟังก์ชันนั้นทำหน้าที่อะไร -It is a widespread practice to start a function with a verbal prefix which vaguely describes the action. There must be an agreement within the team on the meaning of the prefixes. +เป็นแนวปฏิบัติที่แพร่หลายในการขึ้นต้นชื่อฟังก์ชันด้วยคำกริยาเพื่ออธิบายการกระทำคร่าวๆ ทีมงานควรตกลงกันเรื่องความหมายของคำนำหน้าเหล่านี้ให้ชัดเจน -For instance, functions that start with `"show"` usually show something. +ตัวอย่างเช่น ฟังก์ชันที่ขึ้นต้นด้วย `"show"` มักจะแสดงบางอย่าง -Function starting with... +ฟังก์ชันที่ขึ้นต้นด้วย... -- `"get…"` -- return a value, -- `"calc…"` -- calculate something, -- `"create…"` -- create something, -- `"check…"` -- check something and return a boolean, etc. +- `"get…"` -- คืนค่าบางอย่าง +- `"calc…"` -- คำนวณบางอย่าง +- `"create…"` -- สร้างบางอย่าง +- `"check…"` -- ตรวจสอบบางอย่างและคืนค่าบูลีน ฯลฯ -Examples of such names: +ตัวอย่างชื่อฟังก์ชันเหล่านี้: ```js no-beautify -showMessage(..) // shows a message -getAge(..) // returns the age (gets it somehow) -calcSum(..) // calculates a sum and returns the result -createForm(..) // creates a form (and usually returns it) -checkPermission(..) // checks a permission, returns true/false +showMessage(..) // แสดงข้อความ +getAge(..) // คืนค่าอายุ (ได้ค่ามาด้วยวิธีใดวิธีหนึ่ง) +calcSum(..) // คำนวณผลรวมและคืนผลลัพธ์ +createForm(..) // สร้างฟอร์ม (และมักจะคืนค่าฟอร์มนั้น) +checkPermission(..) // ตรวจสอบสิทธิ์ คืนค่า true/false ``` -With prefixes in place, a glance at a function name gives an understanding what kind of work it does and what kind of value it returns. +เมื่อใช้คำนำหน้าแล้ว เพียงแค่มองชื่อฟังก์ชันก็พอจะเข้าใจได้ว่ามันทำงานแบบไหนและคืนค่าประเภทใด -```smart header="One function -- one action" -A function should do exactly what is suggested by its name, no more. +```smart header="หนึ่งฟังก์ชัน -- หนึ่งการกระทำ" +ฟังก์ชันควรทำในสิ่งที่ชื่อของมันบอกไว้ ไม่มากไปกว่านั้น -Two independent actions usually deserve two functions, even if they are usually called together (in that case we can make a 3rd function that calls those two). +การกระทำสองอย่างที่เป็นอิสระจากกัน มักสมควรแยกเป็นสองฟังก์ชัน แม้ว่าปกติจะถูกเรียกใช้ด้วยกัน (ในกรณีนั้นเราอาจสร้างฟังก์ชันที่สามเพื่อเรียกใช้ทั้งสองฟังก์ชันนั้น) -A few examples of breaking this rule: +ตัวอย่างที่ละเมิดกฎข้อนี้: -- `getAge` -- would be bad if it shows an `alert` with the age (should only get). -- `createForm` -- would be bad if it modifies the document, adding a form to it (should only create it and return). -- `checkPermission` -- would be bad if it displays the `access granted/denied` message (should only perform the check and return the result). +- `getAge` -- จะไม่ดีถ้ามันแสดง `alert` บอกอายุด้วย (ควรแค่ดึงค่าอายุเท่านั้น) +- `createForm` -- จะไม่ดีถ้ามันแก้ไขเอกสารด้วยการเพิ่มฟอร์มเข้าไป (ควรแค่สร้างฟอร์มและคืนค่า) +- `checkPermission` -- จะไม่ดีถ้ามันแสดงข้อความ `อนุญาต/ไม่อนุญาตให้เข้าถึง` (ควรแค่ตรวจสอบและคืนผลลัพธ์) -These examples assume common meanings of prefixes. You and your team are free to agree on other meanings, but usually they're not much different. In any case, you should have a firm understanding of what a prefix means, what a prefixed function can and cannot do. All same-prefixed functions should obey the rules. And the team should share the knowledge. +ตัวอย่างเหล่านี้สมมติความหมายทั่วไปของคำนำหน้า คุณและทีมสามารถตกลงกันถึงความหมายอื่นๆ ได้ แต่โดยปกติมักจะไม่ค่อยแตกต่างกันมาก ไม่ว่าอย่างไร คุณควรเข้าใจชัดเจนว่าคำนำหน้าหมายถึงอะไร ฟังก์ชันที่มีคำนำหน้าสามารถและไม่ควรทำอะไรได้บ้าง ฟังก์ชันที่มีคำนำหน้าเดียวกันทั้งหมดควรปฏิบัติตามกฎเดียวกัน และทีมควรแบ่งปันความรู้นี้ร่วมกัน ``` -```smart header="Ultrashort function names" -Functions that are used *very often* sometimes have ultrashort names. +```smart header="ชื่อฟังก์ชันที่สั้นมากๆ" +ฟังก์ชันที่ถูกใช้ *บ่อยมากๆ* บางครั้งอาจมีชื่อที่สั้นมากๆ +<<<<<<< HEAD +เช่น เฟรมเวิร์ค [jQuery](https://jquery.com/) กำหนดฟังก์ชันชื่อ `$` ส่วนไลบรารี [Lodash](https://lodash.com/) มีฟังก์ชันหลักชื่อ `_` +======= For example, the [jQuery](https://jquery.com/) framework defines a function with `$`. The [Lodash](https://lodash.com/) library has its core function named `_`. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -These are exceptions. Generally function names should be concise and descriptive. +แต่สิ่งเหล่านี้เป็นข้อยกเว้น โดยทั่วไปแล้วชื่อฟังก์ชันควรกระชับและบ่งบอกความหมายได้ชัดเจน ``` -## Functions == Comments +## ฟังก์ชัน == คอมเมนต์ -Functions should be short and do exactly one thing. If that thing is big, maybe it's worth it to split the function into a few smaller functions. Sometimes following this rule may not be that easy, but it's definitely a good thing. +ฟังก์ชันควรสั้นและทำเพียงหนึ่งสิ่งอย่างชัดเจน ถ้าสิ่งนั้นใหญ่เกินไป อาจคุ้มค่าที่จะแยกฟังก์ชันออกเป็นฟังก์ชันเล็กๆ สองสามอัน บางครั้งอาจไม่ง่ายนักที่จะทำตามกฎนี้ แต่มันเป็นสิ่งที่ดีอย่างแน่นอน -A separate function is not only easier to test and debug -- its very existence is a great comment! +ฟังก์ชันที่แยกออกมา นอกจากจะทดสอบและดีบักได้ง่ายกว่าแล้ว การมีอยู่ของมันยังเป็นคอมเมนต์ที่ดีเยี่ยมอีกด้วย! -For instance, compare the two functions `showPrimes(n)` below. Each one outputs [prime numbers](https://en.wikipedia.org/wiki/Prime_number) up to `n`. +ยกตัวอย่างเช่น เปรียบเทียบฟังก์ชัน `showPrimes(n)` สองอันด้านล่าง แต่ละอันแสดงผล [จำนวนเฉพาะ](https://en.wikipedia.org/wiki/Prime_number) จนถึง `n` -The first variant uses a label: +แบบแรกใช้ label: ```js function showPrimes(n) { @@ -483,12 +543,12 @@ function showPrimes(n) { if (i % j == 0) continue nextPrime; } - alert( i ); // a prime + alert( i ); // จำนวนเฉพาะ } } ``` -The second variant uses an additional function `isPrime(n)` to test for primality: +แบบที่สองใช้ฟังก์ชันเสริม `isPrime(n)` เพื่อตรวจสอบว่าเป็นจำนวนเฉพาะหรือไม่: ```js function showPrimes(n) { @@ -496,7 +556,7 @@ function showPrimes(n) { for (let i = 2; i < n; i++) { *!*if (!isPrime(i)) continue;*/!* - alert(i); // a prime + alert(i); // จำนวนเฉพาะ } } @@ -508,32 +568,36 @@ function isPrime(n) { } ``` -The second variant is easier to understand, isn't it? Instead of the code piece we see a name of the action (`isPrime`). Sometimes people refer to such code as *self-describing*. +แบบที่สองเข้าใจง่ายกว่าใช่ไหม? แทนที่จะเห็นส่วนโค้ด เราเห็นชื่อการกระทำ (`isPrime`) บางครั้งผู้คนเรียกโค้ดแบบนี้ว่า *อธิบายตัวเอง* -So, functions can be created even if we don't intend to reuse them. They structure the code and make it readable. +ดังนั้นเราสามารถสร้างฟังก์ชันได้แม้ไม่ได้ตั้งใจจะนำมาใช้ซ้ำ มันจัดโครงสร้างโค้ดและทำให้อ่านง่ายขึ้น -## Summary +## สรุป -A function declaration looks like this: +การประกาศฟังก์ชันมีหน้าตาแบบนี้: ```js function name(parameters, delimited, by, comma) { /* code */ -} +} ``` -- Values passed to a function as parameters are copied to its local variables. -- A function may access outer variables. But it works only from inside out. The code outside of the function doesn't see its local variables. -- A function can return a value. If it doesn't, then its result is `undefined`. +- ค่าที่ส่งเข้าไปในฟังก์ชันผ่านพารามิเตอร์จะถูกคัดลอกไปเป็นตัวแปรภายในฟังก์ชั่น +- ฟังก์ชันสามารถเข้าถึงตัวแปรภายนอกได้ แต่มันจะทำงานจากด้านในออกไปด้านนอกเท่านั้น โค้ดภายนอกฟังก์ชันจะไม่เห็นตัวแปรภายในฟังก์ชั่นของมัน +- ฟังก์ชันสามารถคืนค่าได้ ถ้าไม่คืนค่า ผลลัพธ์จะเป็น `undefined` -To make the code clean and easy to understand, it's recommended to use mainly local variables and parameters in the function, not outer variables. +เพื่อให้โค้ดสะอาดและเข้าใจง่าย แนะนำให้ใช้ตัวแปรภายในฟังก์ชั่นและพารามิเตอร์ในฟังก์ชันเป็นหลัก ไม่ใช้ตัวแปรภายนอก +<<<<<<< HEAD +การทำความเข้าใจฟังก์ชันที่รับพารามิเตอร์ ทำงานกับมัน และคืนผลลัพธ์จะง่ายกว่าฟังก์ชันที่ไม่รับพารามิเตอร์แต่ไปแก้ไขตัวแปรภายนอก ซึ่งถือเป็นผลข้างเคียง +======= It is always easier to understand a function which gets parameters, works with them and returns a result than a function which gets no parameters, but modifies outer variables as a side effect. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Function naming: +การตั้งชื่อฟังก์ชัน: -- A name should clearly describe what the function does. When we see a function call in the code, a good name instantly gives us an understanding what it does and returns. -- A function is an action, so function names are usually verbal. -- There exist many well-known function prefixes like `create…`, `show…`, `get…`, `check…` and so on. Use them to hint what a function does. +- ชื่อควรบอกชัดเจนว่าฟังก์ชันทำอะไร เมื่อเห็นการเรียกฟังก์ชันในโค้ด ชื่อที่ดีจะให้ความเข้าใจในทันทีว่ามันทำอะไรและคืนค่าอะไร +- ฟังก์ชันคือการกระทำ ดังนั้นชื่อฟังก์ชันมักเป็นคำกริยา +- มีคำนำหน้าฟังก์ชันที่ใช้กันแพร่หลายเช่น `create…`, `show…`, `get…`, `check…` เป็นต้น ให้ใช้เป็นตัวบอกใบ้ว่าฟังก์ชันทำอะไร -Functions are the main building blocks of scripts. Now we've covered the basics, so we actually can start creating and using them. But that's only the beginning of the path. We are going to return to them many times, going more deeply into their advanced features. +ฟังก์ชันเป็นบล็อกสำคัญในการสร้างสคริปต์ ตอนนี้เราได้เรียนรู้พื้นฐานแล้ว เราจึงสามารถเริ่มสร้างและใช้มันได้จริงๆ แต่นี่เป็นเพียงจุดเริ่มต้นของเส้นทาง เรายังจะกลับมาที่ฟังก์ชันอีกหลายครั้งเพื่อศึกษาฟีเจอร์ขั้นสูงต่างๆ ให้ลึกซึ้งยิ่งขึ้น \ No newline at end of file diff --git a/1-js/02-first-steps/16-function-expressions/article.md b/1-js/02-first-steps/16-function-expressions/article.md index c6dd891bd..8834ae51a 100644 --- a/1-js/02-first-steps/16-function-expressions/article.md +++ b/1-js/02-first-steps/16-function-expressions/article.md @@ -1,8 +1,8 @@ -# Function expressions +# นิพจน์ฟังก์ชัน -In JavaScript, a function is not a "magical language structure", but a special kind of value. +ใน JavaScript ฟังก์ชันไม่ใช่ "โครงสร้างพิเศษทางภาษา" แต่เป็นค่าชนิดหนึ่งที่มีลักษณะเฉพาะ -The syntax that we used before is called a *Function Declaration*: +รูปแบบที่เราใช้ก่อนหน้านี้เรียกว่า *การประกาศฟังก์ชัน* (Function Declaration): ```js function sayHi() { @@ -10,11 +10,11 @@ function sayHi() { } ``` -There is another syntax for creating a function that is called a *Function Expression*. +มีอีกวิธีหนึ่งในการสร้างฟังก์ชันที่เรียกว่า *นิพจน์ฟังก์ชัน* (Function Expression) -It allows us to create a new function in the middle of any expression. +ซึ่งช่วยให้เราสามารถสร้างฟังก์ชันใหม่ได้ในทุกๆ นิพจน์ (expression) -For example: +ตัวอย่างเช่น: ```js let sayHi = function() { @@ -22,21 +22,21 @@ let sayHi = function() { }; ``` -Here we can see a variable `sayHi` getting a value, the new function, created as `function() { alert("Hello"); }`. +ในที่นี้เราเห็นตัวแปร `sayHi` ได้รับค่าเป็นฟังก์ชันใหม่ที่สร้างขึ้นด้วย `function() { alert("Hello"); }` -As the function creation happens in the context of the assignment expression (to the right side of `=`), this is a *Function Expression*. +เนื่องจากการสร้างฟังก์ชันเกิดขึ้นในบริบทของนิพจน์การกำหนดค่า (ทางขวาของเครื่องหมาย `=`) จึงเป็นนิพจน์ฟังก์ชัน -Please note, there's no name after the `function` keyword. Omitting a name is allowed for Function Expressions. +โปรดสังเกตว่าไม่มีชื่อหลังคำสำคัญ `function` การละเว้นชื่อนั้นอนุญาตสำหรับนิพจน์ฟังก์ชัน -Here we immediately assign it to the variable, so the meaning of these code samples is the same: "create a function and put it into the variable `sayHi`". +ในที่นี้เรากำหนดค่าให้กับตัวแปรทันที ดังนั้นความหมายของตัวอย่างโค้ดเหล่านี้จึงเหมือนกันคือ "สร้างฟังก์ชันและเก็บลงในตัวแปร `sayHi`" -In more advanced situations, that we'll come across later, a function may be created and immediately called or scheduled for a later execution, not stored anywhere, thus remaining anonymous. +ในสถานการณ์ที่ซับซ้อนขึ้นซึ่งเราจะเจอในภายหลัง ฟังก์ชันอาจถูกสร้างขึ้นและเรียกใช้ทันที หรือกำหนดเวลาเพื่อใช้ในภายหลัง โดยไม่เก็บไว้ที่ใดเลย จึงไม่มีชื่อ (anonymous) -## Function is a value +## ฟังก์ชันคือค่า -Let's reiterate: no matter how the function is created, a function is a value. Both examples above store a function in the `sayHi` variable. +ขอย้ำอีกครั้ง: ไม่ว่าฟังก์ชันจะถูกสร้างมาอย่างไร มันคือค่าชนิดหนึ่ง ตัวอย่างทั้งสองด้านบนเก็บฟังก์ชันไว้ในตัวแปร `sayHi` -We can even print out that value using `alert`: +เราสามารถแสดงค่านั้นผ่าน `alert` ได้ด้วย: ```js run function sayHi() { @@ -44,41 +44,41 @@ function sayHi() { } *!* -alert( sayHi ); // shows the function code +alert( sayHi ); // แสดงโค้ดฟังก์ชัน */!* ``` -Please note that the last line does not run the function, because there are no parentheses after `sayHi`. There are programming languages where any mention of a function name causes its execution, but JavaScript is not like that. +โปรดสังเกตว่าบรรทัดสุดท้ายไม่ได้เรียกใช้ฟังก์ชัน เพราะไม่มีวงเล็บหลัง `sayHi` มีภาษาโปรแกรมบางภาษาที่เมื่อพูดถึงชื่อฟังก์ชันจะทำให้เกิดการเรียกใช้ทันที แต่ JavaScript ไม่เป็นเช่นนั้น -In JavaScript, a function is a value, so we can deal with it as a value. The code above shows its string representation, which is the source code. +ใน JavaScript ฟังก์ชันเป็นค่าประเภทหนึ่ง เราจึงสามารถจัดการกับมันเหมือนกับค่าประเภทอื่นๆ โค้ดด้านบนแสดงการแปลงเป็นสตริง ซึ่งก็คือซอร์สโค้ดนั่นเอง -Surely, a function is a special value, in the sense that we can call it like `sayHi()`. +แน่นอนว่าฟังก์ชันเป็นค่าพิเศษ ตรงที่เราสามารถเรียกใช้มันได้ เช่น `sayHi()` -But it's still a value. So we can work with it like with other kinds of values. +แต่มันก็ยังคงเป็นค่าอยู่ เราจึงทำงานกับมันได้เหมือนกับค่าประเภทอื่นๆ -We can copy a function to another variable: +เราสามารถคัดลอกฟังก์ชันไปยังตัวแปรอื่นได้: ```js run no-beautify -function sayHi() { // (1) create +function sayHi() { // (1) สร้าง alert( "Hello" ); } -let func = sayHi; // (2) copy +let func = sayHi; // (2) คัดลอก -func(); // Hello // (3) run the copy (it works)! -sayHi(); // Hello // this still works too (why wouldn't it) +func(); // Hello // (3) เรียกใช้สำเนา (ใช้ได้)! +sayHi(); // Hello // ตัวต้นฉบับยังใช้ได้เหมือนเดิม (แน่นอน) ``` -Here's what happens above in detail: +นี่คือสิ่งที่เกิดขึ้นในรายละเอียด: -1. The Function Declaration `(1)` creates the function and puts it into the variable named `sayHi`. -2. Line `(2)` copies it into the variable `func`. Please note again: there are no parentheses after `sayHi`. If there were, then `func = sayHi()` would write *the result of the call* `sayHi()` into `func`, not *the function* `sayHi` itself. -3. Now the function can be called as both `sayHi()` and `func()`. +1. การประกาศฟังก์ชัน `(1)` สร้างฟังก์ชันและเก็บไว้ในตัวแปรชื่อ `sayHi` +2. บรรทัด `(2)` คัดลอกมันไปยังตัวแปร `func` โปรดสังเกตอีกครั้ง: ไม่มีวงเล็บหลัง `sayHi` ถ้ามี `func = sayHi()` จะเขียน *ผลลัพธ์จากการเรียกใช้* `sayHi()` ลงใน `func` ไม่ใช่เขียน *ฟังก์ชัน* `sayHi` เอง +3. ตอนนี้ฟังก์ชันสามารถเรียกได้ทั้งในชื่อ `sayHi()` และ `func()` -We could also have used a Function Expression to declare `sayHi`, in the first line: +เราสามารถใช้นิพจน์ฟังก์ชันเพื่อประกาศ `sayHi` ในบรรทัดแรกก็ได้: ```js -let sayHi = function() { // (1) create +let sayHi = function() { // (1) สร้าง alert( "Hello" ); }; @@ -86,11 +86,16 @@ let func = sayHi; //(2) // ... ``` -Everything would work the same. +ทุกอย่างจะทำงานเหมือนเดิม +<<<<<<< HEAD +```smart header="ทำไมต้องมีเครื่องหมายอัฒภาคตามหลัง?" +คุณอาจสงสัยว่าทำไมนิพจน์ฟังก์ชันถึงต้องมีเครื่องหมายอัฒภาค `;` ท้ายประโยค แต่การประกาศฟังก์ชันไม่ต้องมี: +======= ````smart header="Why is there a semicolon at the end?" You might wonder, why do Function Expressions have a semicolon `;` at the end, but Function Declarations do not: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js function sayHi() { @@ -102,27 +107,26 @@ let sayHi = function() { }*!*;*/!* ``` -The answer is simple: a Function Expression is created here as `function(…) {…}` inside the assignment statement: `let sayHi = …;`. The semicolon `;` is recommended at the end of the statement, it's not a part of the function syntax. +คำตอบคือ: นิพจน์ฟังก์ชันถูกสร้างขึ้นในรูปแบบ `function(…) {…}` ภายในประโยคการกำหนดค่า: `let sayHi = …;` ควรมีเครื่องหมายอัฒภาค `;` ท้ายประโยค มันไม่ใช่ส่วนหนึ่งของไวยากรณ์ฟังก์ชัน -The semicolon would be there for a simpler assignment, such as `let sayHi = 5;`, and it's also there for a function assignment. -```` +เครื่องหมายอัฒภาคจะอยู่ในการกำหนดค่าทั่วไป เช่น `let sayHi = 5;` และอยู่ในการกำหนดค่าฟังก์ชันเช่นกัน -## Callback functions +## ฟังก์ชันคอลแบ็ก -Let's look at more examples of passing functions as values and using function expressions. +มาดูตัวอย่างเพิ่มเติมเกี่ยวกับการส่งฟังก์ชันเป็นค่า และการใช้นิพจน์ฟังก์ชันกัน -We'll write a function `ask(question, yes, no)` with three parameters: +เราจะเขียนฟังก์ชัน `ask(question, yes, no)` ที่มีสามพารามิเตอร์: `question` -: Text of the question +: ข้อความของคำถาม `yes` -: Function to run if the answer is "Yes" +: ฟังก์ชันที่จะรันหากคำตอบคือ "ใช่" `no` -: Function to run if the answer is "No" +: ฟังก์ชันที่จะรันหากคำตอบคือ "ไม่" -The function should ask the `question` and, depending on the user's answer, call `yes()` or `no()`: +ฟังก์ชันควรถาม `question` และเรียกใช้ `yes()` หรือ `no()` ตามคำตอบของผู้ใช้: ```js run *!* @@ -140,17 +144,25 @@ function showCancel() { alert( "You canceled the execution." ); } -// usage: functions showOk, showCancel are passed as arguments to ask +// การใช้งาน: ส่งฟังก์ชัน showOk, showCancel เป็นอาร์กิวเมนต์ให้ ask ask("Do you agree?", showOk, showCancel); ``` +<<<<<<< HEAD +ในทางปฏิบัติ ฟังก์ชันเหล่านี้มีประโยชน์มาก ความแตกต่างหลักระหว่าง `ask` ในชีวิตจริงกับตัวอย่างข้างต้นคือ ฟังก์ชันในชีวิตจริงใช้วิธีที่ซับซ้อนกว่าในการโต้ตอบกับผู้ใช้ นอกเหนือจากการใช้ `confirm` ธรรมดา ในเบราว์เซอร์ ฟังก์ชันเหล่านี้มักสร้างหน้าต่างคำถามที่สวยงาม แต่นั่นเป็นอีกเรื่องหนึ่ง +======= In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such functions usually draw a nice-looking question window. But that's another story. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -**The arguments `showOk` and `showCancel` of `ask` are called *callback functions* or just *callbacks*.** +**อาร์กิวเมนต์ `showOk` และ `showCancel` ของ `ask` เรียกว่า *ฟังก์ชันคอลแบ็ก* หรือ *คอลแบ็ก*** -The idea is that we pass a function and expect it to be "called back" later if necessary. In our case, `showOk` becomes the callback for "yes" answer, and `showCancel` for "no" answer. +แนวคิดคือ เราส่งฟังก์ชันไป และคาดหวังว่ามันจะถูก "เรียกกลับ (called back)" ในภายหลังหากจำเป็น ในกรณีของเรา `showOk` เป็นคอลแบ็กสำหรับคำตอบ "ใช่" และ `showCancel` สำหรับคำตอบ "ไม่" +<<<<<<< HEAD +เราสามารถใช้นิพจน์ฟังก์ชันเพื่อเขียนฟังก์ชันเทียบเท่าที่สั้นกว่าได้: +======= We can use Function Expressions to write an equivalent, shorter function: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js run no-beautify function ask(question, yes, no) { @@ -167,59 +179,68 @@ ask( */!* ``` -Here, functions are declared right inside the `ask(...)` call. They have no name, and so are called *anonymous*. Such functions are not accessible outside of `ask` (because they are not assigned to variables), but that's just what we want here. +ในที่นี้ ฟังก์ชันถูกประกาศขึ้นภายในการเรียก `ask(...)` โดยตรง โดยไม่มีการระบุชื่อ จึงเรียกว่า *anonymous (ไม่มีชื่อ)* ฟังก์ชันเหล่านี้ไม่สามารถเข้าถึงได้จากภายนอกของ `ask` (เพราะไม่ได้กำหนดให้กับตัวแปร) แต่นั่นแหละคือสิ่งที่เราต้องการในที่นี้ -Such code appears in our scripts very naturally, it's in the spirit of JavaScript. +โค้ดลักษณะนี้ปรากฏในสคริปต์ของเราได้อย่างเป็นธรรมชาติ มันเป็นไปตามหลักการของภาษา JavaScript -```smart header="A function is a value representing an \"action\"" -Regular values like strings or numbers represent the *data*. +```smart header="ฟังก์ชันคือค่าที่แทนการ \"กระทำ\"" +ค่าปกติ เช่น สตริงหรือตัวเลข แสดงถึง *ข้อมูล* -A function can be perceived as an *action*. +สามารถมองฟังก์ชันเป็น *การกระทำ* ได้ -We can pass it between variables and run when we want. +เราสามารถส่งผ่านมันไประหว่างตัวแปร และสั่งให้ทำงานเมื่อใดก็ได้ที่ต้องการ ``` +## นิพจน์ฟังก์ชัน (Function Expression) กับ การประกาศฟังก์ชัน (Function Declaration) -## Function Expression vs Function Declaration +มาสรุปความแตกต่างสำคัญระหว่างการประกาศฟังก์ชันและนิพจน์ฟังก์ชันกัน -Let's formulate the key differences between Function Declarations and Expressions. +ประการแรก ในแง่วากยสัมพันธ์: วิธีแยกแยะทั้งสองแบบในโค้ด +<<<<<<< HEAD +- *การประกาศฟังก์ชัน:* ฟังก์ชันที่ประกาศเป็นประโยคแยกต่างหาก ในเนื้อหาหลักของโค้ด: +======= First, the syntax: how to differentiate between them in the code. - *Function Declaration:* a function, declared as a separate statement, in the main code flow: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js - // Function Declaration + // การประกาศฟังก์ชัน function sum(a, b) { return a + b; } ``` +<<<<<<< HEAD +- *นิพจน์ฟังก์ชัน:* ฟังก์ชันที่ถูกสร้างภายในนิพจน์ หรือภายในโครงสร้างไวยากรณ์อื่นๆ ในที่นี้ ฟังก์ชันถูกสร้างขึ้นทางด้านขวาของ "นิพจน์การกำหนดค่า" `=`: +======= - *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created on the right side of the "assignment expression" `=`: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js - // Function Expression + // นิพจน์ฟังก์ชัน let sum = function(a, b) { return a + b; }; ``` -The more subtle difference is *when* a function is created by the JavaScript engine. +ความแตกต่างที่ละเอียดอ่อนกว่าคือ เวลาที่ฟังก์ชันถูกสร้างโดยเอนจินของ JavaScript *เมื่อใด* -**A Function Expression is created when the execution reaches it and is usable only from that moment.** +**นิพจน์ฟังก์ชัน ถูกสร้างเมื่อการประมวลผลมาถึงมัน และใช้งานได้ตั้งแต่จุดนั้นเป็นต้นไป** -Once the execution flow passes to the right side of the assignment `let sum = function…` -- here we go, the function is created and can be used (assigned, called, etc. ) from now on. +เมื่อโฟลว์การประมวลผลผ่านไปถึงทางด้านขวาของการกำหนดค่า `let sum = function…` -- ฟังก์ชันก็จะถูกสร้างขึ้น และสามารถใช้งานได้ตั้งแต่ตอนนี้เป็นต้นไป (กำหนดค่า เรียกใช้ ฯลฯ) -Function Declarations are different. +การประกาศฟังก์ชันนั้นแตกต่างออกไป -**A Function Declaration can be called earlier than it is defined.** +**การประกาศฟังก์ชันสามารถเรียกใช้ได้ก่อนที่จะมีการประกาศ** -For example, a global Function Declaration is visible in the whole script, no matter where it is. +ยกตัวอย่างเช่น การประกาศฟังก์ชันระดับโกลบอลจะมองเห็นได้ทั่วทั้งสคริปต์ ไม่ว่าจะอยู่ตรงไหน -That's due to internal algorithms. When JavaScript prepares to run the script, it first looks for global Function Declarations in it and creates the functions. We can think of it as an "initialization stage". +นั่นเป็นเพราะอัลกอริทึมภายใน เมื่อ JavaScript เตรียมตัวที่จะรันสคริปต์ มันจะมองหา การประกาศฟังก์ชันระดับโกลบอลก่อนเป็นอันดับแรก แล้วทำการสร้างฟังก์ชันเหล่านั้นขึ้น เราอาจมองเป็น "ขั้นตอนการเตรียมการ" -And after all Function Declarations are processed, the code is executed. So it has access to these functions. +และหลังจากประมวลผล การประกาศฟังก์ชันทั้งหมดแล้ว จึงค่อยประมวลผลโค้ดตามปกติ ดังนั้นโค้ดจึงสามารถเข้าถึงฟังก์ชันเหล่านั้นได้ -For example, this works: +ตัวอย่างเช่น โค้ดนี้สามารถทำงานได้: ```js run refresh untrusted *!* @@ -231,34 +252,34 @@ function sayHi(name) { } ``` -The Function Declaration `sayHi` is created when JavaScript is preparing to start the script and is visible everywhere in it. +การประกาศฟังก์ชัน `sayHi` ถูกสร้างขึ้นตอนที่ JavaScript กำลังเตรียมจะเริ่มสคริปต์ และมองเห็นได้ทั่วทั้งสคริปต์ -...If it were a Function Expression, then it wouldn't work: +...แต่ถ้าเป็น นิพจน์ฟังก์ชันก็จะใช้งานไม่ได้: ```js run refresh untrusted *!* sayHi("John"); // error! */!* -let sayHi = function(name) { // (*) no magic any more +let sayHi = function(name) { // (*) ไม่มีเวทมนต์อีกต่อไป alert( `Hello, ${name}` ); }; ``` -Function Expressions are created when the execution reaches them. That would happen only in the line `(*)`. Too late. +นิพจน์ฟังก์ชันจะถูกสร้างก็ต่อเมื่อการประมวลผลมาถึงมัน ซึ่งจะเกิดขึ้นที่บรรทัด `(*)` เท่านั้น ช้าไปแล้ว -Another special feature of Function Declarations is their block scope. +อีกคุณสมบัติพิเศษของ การประกาศฟังก์ชันคือขอบเขตแบบบล็อก -**In strict mode, when a Function Declaration is within a code block, it's visible everywhere inside that block. But not outside of it.** +**ในโหมดเข้มงวด เมื่อการประกาศฟังก์ชันอยู่ภายในบล็อกโค้ด มันจะมองเห็นได้ทั่วภายในบล็อกนั้น แต่มองไม่เห็นภายนอกบล็อก** -For instance, let's imagine that we need to declare a function `welcome()` depending on the `age` variable that we get during runtime. And then we plan to use it some time later. +ยกตัวอย่าง สมมติเราต้องการประกาศฟังก์ชัน `welcome()` โดยขึ้นอยู่กับค่าตัวแปร `age` ที่ได้มาระหว่างรันไทม์ และเราวางแผนจะใช้มันในภายหลัง -If we use Function Declaration, it won't work as intended: +หากใช้ การประกาศฟังก์ชันมันจะไม่ทำงานตามที่ตั้งใจ: ```js run let age = prompt("What is your age?", 18); -// conditionally declare a function +// ประกาศฟังก์ชันตามเงื่อนไข if (age < 18) { function welcome() { @@ -273,16 +294,19 @@ if (age < 18) { } -// ...use it later +// ...ใช้ในภายหลัง *!* welcome(); // Error: welcome is not defined */!* ``` -That's because a Function Declaration is only visible inside the code block in which it resides. +เราจะทำอย่างไรเพื่อให้ `welcome` มองเห็นได้จากภายนอก `if`? -Here's another example: +วิธีที่ถูกต้องคือการใช้นิพจน์ฟังก์ชันและกำหนดค่า `welcome` ให้กับตัวแปรที่ประกาศไว้นอก `if` ซึ่งมีการมองเห็นที่เหมาะสม +<<<<<<< HEAD +โค้ดนี้ทำงานตามที่ตั้งใจไว้: +======= ```js run let age = 16; // take 16 as an example @@ -319,6 +343,7 @@ What can we do to make `welcome` visible outside of `if`? The correct approach would be to use a Function Expression and assign `welcome` to the variable that is declared outside of `if` and has the proper visibility. This code works as intended: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js run let age = prompt("What is your age?", 18); @@ -340,11 +365,11 @@ if (age < 18) { } *!* -welcome(); // ok now +welcome(); // ตอนนี้ใช้ได้แล้ว */!* ``` -Or we could simplify it even further using a question mark operator `?`: +หรือเราสามารถทำให้มันเรียบง่ายขึ้นอีกโดยใช้ตัวดำเนินการเครื่องหมายคำถาม `?`: ```js run let age = prompt("What is your age?", 18); @@ -354,27 +379,32 @@ let welcome = (age < 18) ? function() { alert("Greetings!"); }; *!* -welcome(); // ok now +welcome(); // ตอนนี้ใช้ได้แล้ว */!* ``` +<<<<<<< HEAD +```smart header="เมื่อไหร่ควรเลือกใช้การประกาศฟังก์ชัน หรือนิพจน์ฟังก์ชัน?" +โดยหลักการทั่วไป เมื่อเราต้องการประกาศฟังก์ชัน สิ่งแรกที่ควรพิจารณาคือใช้ไวยากรณ์แบบการประกาศฟังก์ชัน เพราะมันให้อิสระในการจัดวางโค้ดมากกว่า เนื่องจากเราสามารถเรียกใช้ฟังก์ชันเหล่านั้นได้ก่อนที่จะมีการประกาศ +======= ```smart header="When to choose Function Declaration versus Function Expression?" As a rule of thumb, when we need to declare a function, the first thing to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -That's also better for readability, as it's easier to look up `function f(…) {…}` in the code than `let f = function(…) {…};`. Function Declarations are more "eye-catching". +นอกจากนี้ยังอ่านทำความเข้าใจง่ายกว่า เพราะมองหา `function f(…) {…}` ในโค้ดได้ง่ายกว่า `let f = function(…) {…};` การประกาศฟังก์ชันนั้น "โดดเด่นมากกว่า" -...But if a Function Declaration does not suit us for some reason, or we need a conditional declaration (we've just seen an example), then Function Expression should be used. +...แต่ถ้าการประกาศฟังก์ชันไม่เหมาะสมกับเราด้วยเหตุผลบางประการ หรือเราต้องการประกาศแบบมีเงื่อนไข (เราเพิ่งเห็นตัวอย่างไป) ควรใช้นิพจน์ฟังก์ชันแทน ``` -## Summary +## สรุป -- Functions are values. They can be assigned, copied or declared in any place of the code. -- If the function is declared as a separate statement in the main code flow, that's called a "Function Declaration". -- If the function is created as a part of an expression, it's called a "Function Expression". -- Function Declarations are processed before the code block is executed. They are visible everywhere in the block. -- Function Expressions are created when the execution flow reaches them. +- ฟังก์ชันคือค่า สามารถกำหนดค่า คัดลอก หรือประกาศไว้ที่ใดก็ได้ในโค้ด +- ถ้าฟังก์ชันถูกประกาศเป็นประโยคแยกต่างหากในลำดับการทำงานหลักของโค้ด เรียกว่า "การประกาศฟังก์ชัน" +- ถ้าฟังก์ชันถูกสร้างขึ้นเป็นส่วนหนึ่งของนิพจน์ เรียกว่า "นิพจน์ฟังก์ชัน" +- การประกาศฟังก์ชัน (Function Declaration) จะถูกประมวลผลก่อนที่บล็อกโค้ดจะเริ่มทำงาน ทำให้มองเห็นได้ทั่วทั้งบล็อก +- นิพจน์ฟังก์ชัน (Function Expression) จะถูกสร้างขึ้นเมื่อลำดับการทำงานมาถึงจุดที่มันอยู่ -In most cases when we need to declare a function, a Function Declaration is preferable, because it is visible prior to the declaration itself. That gives us more flexibility in code organization, and is usually more readable. +ในเกือบทุกกรณีที่เราต้องการประกาศฟังก์ชัน (Function Declaration) เป็นตัวเลือกที่เหมาะสมกว่า เพราะมันมองเห็นได้ก่อนการประกาศจริงๆ ทำให้เรามีความยืดหยุ่นในการจัดวางโค้ดมากขึ้น และมักจะอ่านเข้าใจง่ายกว่า -So we should use a Function Expression only when a Function Declaration is not fit for the task. We've seen a couple of examples of that in this chapter, and will see more in the future. +ดังนั้นเราควรใช้นิพจน์ฟังก์ชันเฉพาะเมื่อการประกาศฟังก์ชันไม่เหมาะสมกับงาน เราได้เห็นตัวอย่างไปบ้างแล้วในบทนี้ และจะเห็นเพิ่มเติมในอนาคต diff --git a/1-js/02-first-steps/17-arrow-functions-basics/article.md b/1-js/02-first-steps/17-arrow-functions-basics/article.md index 50c0d475d..1ef3a3e1b 100644 --- a/1-js/02-first-steps/17-arrow-functions-basics/article.md +++ b/1-js/02-first-steps/17-arrow-functions-basics/article.md @@ -1,16 +1,16 @@ -# Arrow functions, the basics +# ฟังก์ชันลูกศร (Arrow functions) ข้อมูลพื้นฐาน -There's another very simple and concise syntax for creating functions, that's often better than Function Expressions. +มีไวยากรณ์ที่เรียบง่ายและกระชับอีกแบบหนึ่งในการสร้างฟังก์ชัน ซึ่งมักจะดีกว่า Function Expression -It's called "arrow functions", because it looks like this: +เรียกว่า "ฟังก์ชันลูกศร" เพราะมันดูแบบนี้: ```js let func = (arg1, arg2, ..., argN) => expression; ``` -This creates a function `func` that accepts arguments `arg1..argN`, then evaluates the `expression` on the right side with their use and returns its result. +นี่จะสร้างฟังก์ชัน `func` ที่รับอาร์กิวเมนต์ `arg1..argN` จากนั้นจะประเมินค่า `expression` ทางด้านขวาโดยใช้อาร์กิวเมนต์เหล่านั้น แล้วส่งคืนผลลัพธ์ -In other words, it's the shorter version of: +อีกนัยหนึ่ง มันคือเวอร์ชันที่สั้นกว่าของ: ```js let func = function(arg1, arg2, ..., argN) { @@ -18,12 +18,12 @@ let func = function(arg1, arg2, ..., argN) { }; ``` -Let's see a concrete example: +มาดูตัวอย่างที่เป็นรูปธรรมกัน: ```js run let sum = (a, b) => a + b; -/* This arrow function is a shorter form of: +/* ฟังก์ชันลูกศรนี้เป็นรูปแบบสั้นกว่าของ: let sum = function(a, b) { return a + b; @@ -33,22 +33,26 @@ let sum = function(a, b) { alert( sum(1, 2) ); // 3 ``` -As you can see, `(a, b) => a + b` means a function that accepts two arguments named `a` and `b`. Upon the execution, it evaluates the expression `a + b` and returns the result. +ดังที่เห็น `(a, b) => a + b` หมายถึงฟังก์ชันที่รับอาร์กิวเมนต์สองตัว ชื่อ `a` และ `b` เมื่อรันฟังก์ชัน มันจะประเมินนิพจน์ `a + b` และส่งคืนผลลัพธ์ -- If we have only one argument, then parentheses around parameters can be omitted, making that even shorter. +- ถ้าเรามีอาร์กิวเมนต์เพียงตัวเดียว วงเล็บล้อมรอบพารามิเตอร์สามารถละได้ ทำให้มันสั้นลงไปอีก - For example: + ยกตัวอย่างเช่น: ```js run *!* let double = n => n * 2; - // roughly the same as: let double = function(n) { return n * 2 } + // คล้ายๆ กับ: let double = function(n) { return n * 2 } */!* alert( double(3) ); // 6 ``` +<<<<<<< HEAD +- ถ้าไม่มีอาร์กิวเมนต์เลย วงเล็บจะว่างเปล่า แต่ต้องใส่ไว้: +======= - If there are no arguments, parentheses are empty, but they must be present: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```js run let sayHi = () => alert("Hello!"); @@ -56,9 +60,9 @@ As you can see, `(a, b) => a + b` means a function that accepts two arguments na sayHi(); ``` -Arrow functions can be used in the same way as Function Expressions. +ฟังก์ชันลูกศรสามารถใช้ได้ในลักษณะเดียวกับ Function Expression -For instance, to dynamically create a function: +ยกตัวอย่างเช่น สำหรับการสร้างฟังก์ชันแบบไดนามิก: ```js run let age = prompt("What is your age?", 18); @@ -70,42 +74,55 @@ let welcome = (age < 18) ? welcome(); ``` -Arrow functions may appear unfamiliar and not very readable at first, but that quickly changes as the eyes get used to the structure. +ฟังก์ชันลูกศรอาจดูไม่คุ้นตาและอ่านยากในตอนแรก แต่พอตาชินกับโครงสร้างแล้ว ก็จะเปลี่ยนไปอย่างรวดเร็ว -They are very convenient for simple one-line actions, when we're just too lazy to write many words. +มันสะดวกมากสำหรับการทำงานง่ายๆ บรรทัดเดียว ในยามที่เรารู้สึกขี้เกียจเขียนโค้ดยาวๆ -## Multiline arrow functions +## ฟังก์ชันลูกศรแบบหลายบรรทัด +<<<<<<< HEAD +ฟังก์ชันลูกศรที่เราเห็นมาจนถึงตอนนี้ค่อนข้างเรียบง่าย โดยรับอาร์กิวเมนต์จากด้านซ้ายของ `=>` ประเมินค่า และส่งคืนนิพจน์ทางขวาโดยใช้อาร์กิวเมนต์เหล่านั้น + +บางครั้งเราต้องการฟังก์ชันที่ซับซ้อนกว่านั้น ที่มีหลายนิพจน์และประโยค ในกรณีนี้ เราสามารถครอบมันด้วยวงเล็บปีกกาได้ ความแตกต่างหลักคือ การใช้วงเล็บปีกกาต้องมีคำสั่ง `return` ภายในเพื่อส่งค่ากลับ (เหมือนฟังก์ชันปกติ) +======= The arrow functions that we've seen so far were very simple. They took arguments from the left of `=>`, evaluated and returned the right-side expression with them. Sometimes we need a more complex function, with multiple expressions and statements. In that case, we can enclose them in curly braces. The major difference is that curly braces require a `return` within them to return a value (just like a regular function does). +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Like this: +ตัวอย่างเช่น: ```js run -let sum = (a, b) => { // the curly brace opens a multiline function +let sum = (a, b) => { // วงเล็บปีกกาเปิดฟังก์ชันแบบหลายบรรทัด let result = a + b; *!* - return result; // if we use curly braces, then we need an explicit "return" + return result; // ถ้าเราใช้วงเล็บปีกกา ต้องใส่ "return" อย่างชัดเจน */!* }; alert( sum(1, 2) ); // 3 ``` -```smart header="More to come" -Here we praised arrow functions for brevity. But that's not all! +```smart header="ยังมีอีกมากมาย" +ที่ผ่านมาเราชื่นชมฟังก์ชันลูกศรในเรื่องความกระชับ แต่นั่นไม่ใช่ทั้งหมด! -Arrow functions have other interesting features. +ฟังก์ชันลูกศรยังมีคุณสมบัติที่น่าสนใจอื่นๆ อีก -To study them in-depth, we first need to get to know some other aspects of JavaScript, so we'll return to arrow functions later in the chapter . +เพื่อศึกษาสิ่งเหล่านั้นอย่างลึกซึ้ง เราจำเป็นต้องมีความรู้เกี่ยวกับแง่มุมอื่นๆ ของ JavaScript ก่อน ดังนั้นเราจะกลับมาพูดถึงฟังก์ชันลูกศรอีกครั้งในบท -For now, we can already use arrow functions for one-line actions and callbacks. +สำหรับตอนนี้ เราสามารถใช้ฟังก์ชันลูกศรกับการทำงานแบบบรรทัดเดียวและฟังก์ชันคอลแบ็กได้แล้ว ``` -## Summary +## สรุป + +<<<<<<< HEAD +ฟังก์ชันลูกศรนั้นใช้สะดวกสำหรับการกระทำง่ายๆ โดยเฉพาะอย่างยิ่งแบบบรรทัดเดียว มีสองรูปแบบดังนี้: +1. ไม่มีวงเล็บปีกกา: `(...args) => expression` -- ทางขวาเป็นนิพจน์: ฟังก์ชันจะประเมินค่าและส่งคืนผลลัพธ์ สามารถละวงเล็บได้ถ้ามีอาร์กิวเมนต์เพียงตัวเดียว เช่น `n => n*2` +2. มีวงเล็บปีกกา: `(...args) => { body }` -- วงเล็บปีกกาช่วยให้เราเขียนหลายคำสั่งภายในฟังก์ชันได้ แต่เราต้องใส่ `return` อย่างชัดเจนเพื่อส่งอะไรบางอย่างกลับ +======= Arrow functions are handy for simple actions, especially for one-liners. They come in two flavors: 1. Without curly braces: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result. Parentheses can be omitted, if there's only a single argument, e.g. `n => n*2`. 2. With curly braces: `(...args) => { body }` -- brackets allow us to write multiple statements inside the function, but we need an explicit `return` to return something. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 diff --git a/1-js/02-first-steps/18-javascript-specials/article.md b/1-js/02-first-steps/18-javascript-specials/article.md index e7ddacac4..d84eb77e0 100644 --- a/1-js/02-first-steps/18-javascript-specials/article.md +++ b/1-js/02-first-steps/18-javascript-specials/article.md @@ -1,23 +1,23 @@ -# JavaScript specials +# ความพิเศษของ JavaScript -This chapter briefly recaps the features of JavaScript that we've learned by now, paying special attention to subtle moments. +บทนี้จะสรุปย่อคุณลักษณะของ JavaScript ที่เราได้เรียนมาจนถึงตอนนี้ โดยให้ความสนใจเป็นพิเศษกับจุดละเอียดอ่อน -## Code structure +## โครงสร้างโค้ด -Statements are delimited with a semicolon: +คำสั่งจะถูกคั่นด้วยเครื่องหมายอัฒภาค (semicolon): ```js run no-beautify alert('Hello'); alert('World'); ``` -Usually, a line-break is also treated as a delimiter, so that would also work: +โดยทั่วไปแล้ว การขึ้นบรรทัดใหม่ก็ถือเป็นตัวคั่นเช่นกัน ดังนั้นแบบนี้ก็ใช้ได้เช่นกัน: ```js run no-beautify alert('Hello') alert('World') ``` -That's called "automatic semicolon insertion". Sometimes it doesn't work, for instance: +เรียกว่า "การแทรกเครื่องหมายอัฒภาคอัตโนมัติ" แต่บางครั้งก็ไม่ทำงาน ยกตัวอย่างเช่น: ```js run alert("There will be an error after this message") @@ -25,27 +25,27 @@ alert("There will be an error after this message") [1, 2].forEach(alert) ``` -Most codestyle guides agree that we should put a semicolon after each statement. +คู่มือรูปแบบการเขียนโค้ดส่วนใหญ่เห็นพ้องกันว่า เราควรใส่เครื่องหมายอัฒภาคหลังแต่ละคำสั่ง -Semicolons are not required after code blocks `{...}` and syntax constructs with them like loops: +ไม่จำเป็นต้องใช้เครื่องหมายอัฒภาคหลังบล็อกโค้ด `{...}` และโครงสร้างทางไวยากรณ์ที่มีบล็อกเหล่านั้น เช่น ลูป: ```js function f() { - // no semicolon needed after function declaration + // ไม่ต้องใส่เครื่องหมายอัฒภาคหลังการประกาศฟังก์ชัน } for(;;) { - // no semicolon needed after the loop + // ไม่ต้องใส่เครื่องหมายอัฒภาคหลังลูป } ``` -...But even if we can put an "extra" semicolon somewhere, that's not an error. It will be ignored. +...แต่แม้ว่าเราจะใส่เครื่องหมายอัฒภาค "เพิ่มเติม" ไว้ที่ใดสักแห่ง ก็ไม่ถือเป็นข้อผิดพลาด มันจะถูกละเว้น -More in: . +อ่านเพิ่มเติมได้ที่: -## Strict mode +## โหมดเข้มงวด (Strict mode) -To fully enable all features of modern JavaScript, we should start scripts with `"use strict"`. +เพื่อเปิดใช้งานคุณลักษณะทั้งหมดของ JavaScript สมัยใหม่อย่างเต็มที่ เราควรเริ่มต้นสคริปต์ด้วย `"use strict"` ```js 'use strict'; @@ -53,57 +53,70 @@ To fully enable all features of modern JavaScript, we should start scripts with ... ``` -The directive must be at the top of a script or at the beginning of a function body. +คำสั่งนี้จะต้องอยู่ที่ด้านบนสุดของสคริปต์ หรือที่จุดเริ่มต้นของ function body +<<<<<<< HEAD +หากไม่มี `"use strict"` ทุกอย่างก็ยังคงทำงานได้ แต่คุณลักษณะบางอย่างจะทำงานในแบบเก่าๆ "แบบเข้ากันได้" โดยทั่วไปเรามักจะต้องการพฤติกรรมแบบสมัยใหม่มากกว่า +======= Without `"use strict"`, everything still works, but some features behave in the old-fashioned, "compatible" way. We'd generally prefer the modern behavior. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Some modern features of the language (like classes that we'll study in the future) enable strict mode implicitly. +คุณลักษณะสมัยใหม่บางอย่างของภาษา (เช่น คลาส ซึ่งเราจะศึกษาในอนาคต) จะเปิดใช้งานโหมดเข้มงวดโดยอัตโนมัติ -More in: . +อ่านเพิ่มเติมได้ที่: -## Variables +## ตัวแปร -Can be declared using: +สามารถประกาศตัวแปรได้โดยใช้: - `let` -- `const` (constant, can't be changed) -- `var` (old-style, will see later) +- `const` (ค่าคงที่ ไม่สามารถเปลี่ยนแปลงได้) +- `var` (แบบเก่า จะได้เห็นในภายหลัง) -A variable name can include: -- Letters and digits, but the first character may not be a digit. -- Characters `$` and `_` are normal, on par with letters. -- Non-Latin alphabets and hieroglyphs are also allowed, but commonly not used. +ชื่อตัวแปรสามารถประกอบด้วย: +- ตัวอักษรและตัวเลข แต่ตัวแรกจะต้องไม่ใช่ตัวเลข +- อักขระ `$` และ `_` เป็นอักขระปกติ เทียบเท่ากับตัวอักษร +- ตัวอักษรที่ไม่ใช่ละตินและอักษรอียิปต์โบราณก็สามารถใช้ได้ แต่ไม่ค่อยนิยมใช้ -Variables are dynamically typed. They can store any value: +ตัวแปรมีการกำหนดชนิดข้อมูลแบบไดนามิก สามารถเก็บค่าใดๆ ก็ได้: ```js let x = 5; x = "John"; ``` -There are 8 data types: +มีชนิดข้อมูลทั้งหมด 8 ชนิด: -- `number` for both floating-point and integer numbers, -- `bigint` for integer numbers of arbitrary length, -- `string` for strings, -- `boolean` for logical values: `true/false`, -- `null` -- a type with a single value `null`, meaning "empty" or "does not exist", -- `undefined` -- a type with a single value `undefined`, meaning "not assigned", -- `object` and `symbol` -- for complex data structures and unique identifiers, we haven't learnt them yet. +- `number` สำหรับตัวเลขทั้งจำนวนจริงและจำนวนเต็ม +- `bigint` สำหรับจำนวนเต็มที่มีความยาวตามต้องการ +- `string` สำหรับข้อความ +- `boolean` สำหรับค่าตรรกะ: `true/false` +- `null` -- ชนิดข้อมูลที่มีค่าเดียวคือ `null` หมายถึง "ว่างเปล่า" หรือ "ไม่มีอยู่" +- `undefined` -- ชนิดข้อมูลที่มีค่าเดียวคือ `undefined` หมายถึง "ยังไม่ได้กำหนดค่า" +- `object` และ `symbol` -- สำหรับโครงสร้างข้อมูลที่ซับซ้อน และตัวระบุที่ไม่ซ้ำกัน เรายังไม่ได้เรียนรู้เกี่ยวกับสิ่งเหล่านี้ -The `typeof` operator returns the type for a value, with two exceptions: +ตัวดำเนินการ `typeof` จะคืนค่าชนิดข้อมูลของค่านั้นๆ โดยมีข้อยกเว้นสองกรณี: ```js -typeof null == "object" // error in the language -typeof function(){} == "function" // functions are treated specially +typeof null == "object" // ข้อผิดพลาดในภาษา +typeof function(){} == "function" // ฟังก์ชันจะถูกจัดการเป็นพิเศษ ``` -More in: and . +อ่านเพิ่มเติมได้ที่: และ -## Interaction +## การโต้ตอบ -We're using a browser as a working environment, so basic UI functions will be: +เนื่องจากเรากำลังใช้เบราว์เซอร์เป็นสภาพแวดล้อมในการทำงาน ฟังก์ชัน UI พื้นฐานจึงประกอบด้วย: [`prompt(question, [default])`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) +<<<<<<< HEAD +: ถาม `question` และคืนค่าสิ่งที่ผู้ใช้ป้อนเข้ามา หรือ `null` หากผู้ใช้คลิก "ยกเลิก" + +[`confirm(question)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) +: ถาม `question` และแนะนำให้เลือกระหว่าง ตกลง และ ยกเลิก ทางเลือกจะถูกส่งคืนเป็น `true/false` + +[`alert(message)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) +: แสดงผล `message` +======= : Ask a `question`, and return either what the visitor entered or `null` if they clicked "cancel". [`confirm(question)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) @@ -111,10 +124,11 @@ We're using a browser as a working environment, so basic UI functions will be: [`alert(message)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) : Output a `message`. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -All these functions are *modal*, they pause the code execution and prevent the visitor from interacting with the page until they answer. +ฟังก์ชันเหล่านี้ทั้งหมดเป็นแบบ *modal* หมายความว่าจะหยุดการทำงานของโค้ด และป้องกันไม่ให้ผู้ใช้โต้ตอบกับหน้าเว็บจนกว่าจะตอบคำถาม -For instance: +ตัวอย่างเช่น: ```js run let userName = prompt("Your name?", "Alice"); @@ -124,61 +138,66 @@ alert( "Visitor: " + userName ); // Alice alert( "Tea wanted: " + isTeaWanted ); // true ``` -More in: . +อ่านเพิ่มเติมได้ที่: -## Operators +## ตัวดำเนินการ (Operators) -JavaScript supports the following operators: +JavaScript รองรับตัวดำเนินการดังต่อไปนี้: -Arithmetical -: Regular: `* + - /`, also `%` for the remainder and `**` for power of a number. +ทางคณิตศาสตร์ +: ปกติ: `* + - /` รวมถึง `%` สำหรับการหารเอาเศษ และ `**` สำหรับการยกกำลัง - The binary plus `+` concatenates strings. And if any of the operands is a string, the other one is converted to string too: + ตัวดำเนินการบวก `+` แบบสองตัวถูกกระทำจะเชื่อมต่อสตริง และถ้าตัวใดตัวหนึ่งเป็นสตริง อีกตัวก็จะถูกแปลงเป็นสตริงด้วยเช่นกัน: ```js run alert( '1' + 2 ); // '12', string alert( 1 + '2' ); // '12', string ``` -Assignments -: There is a simple assignment: `a = b` and combined ones like `a *= 2`. +การกำหนดค่า +: มีการกำหนดค่าธรรมดา: `a = b` และแบบรวมต่างๆ เช่น `a *= 2` +<<<<<<< HEAD +การดำเนินการระดับบิต +: ตัวดำเนินการระดับบิตจะทำงานกับจำนวนเต็ม 32 บิตที่ระดับบิตต่ำสุด: ดูที่ [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) เมื่อต้องการ +======= Bitwise : Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) when they are needed. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Conditional -: The only operator with three parameters: `cond ? resultA : resultB`. If `cond` is truthy, returns `resultA`, otherwise `resultB`. +แบบมีเงื่อนไข +: ตัวดำเนินการเพียงตัวเดียวที่มีสามพารามิเตอร์: `cond ? resultA : resultB` ถ้า `cond` เป็น truthy จะคืนค่า `resultA` ไม่เช่นนั้นจะคืน `resultB` -Logical operators -: Logical AND `&&` and OR `||` perform short-circuit evaluation and then return the value where it stopped (not necessary `true`/`false`). Logical NOT `!` converts the operand to boolean type and returns the inverse value. +ตัวดำเนินการทางตรรกะ +: AND ตรรกะ `&&` และ OR ตรรกะ `||` จะทำการประเมินแบบลัดวงจรและคืนค่าที่มันหยุด (ไม่จำเป็นต้องเป็น `true/false`) NOT ตรรกะ `!` แปลงตัวถูกกระทำเป็น boolean และคืนค่าตรงข้าม -Nullish coalescing operator -: The `??` operator provides a way to choose a defined value from a list of variables. The result of `a ?? b` is `a` unless it's `null/undefined`, then `b`. +ตัวดำเนินการ Nullish coalescing +: ตัวดำเนินการ `??` ให้วิธีเลือกค่าที่ถูกกำหนดจากรายการตัวแปร ผลลัพธ์ของ `a ?? b` คือ `a` เว้นแต่มันจะเป็น `null/undefined` จึงจะเป็น `b` -Comparisons -: Equality check `==` for values of different types converts them to a number (except `null` and `undefined` that equal each other and nothing else), so these are equal: +การเปรียบเทียบ +: การตรวจสอบความเท่ากัน `==` สำหรับค่าที่มีชนิดต่างกันจะแปลงเป็นตัวเลข (ยกเว้น `null` และ `undefined` ซึ่งเท่ากันและไม่เท่ากับอะไรอื่น) ดังนั้นพวกนี้จึงเท่ากัน: ```js run alert( 0 == false ); // true alert( 0 == '' ); // true ``` - Other comparisons convert to a number as well. + การเปรียบเทียบอื่นๆ ก็จะแปลงเป็นตัวเลขด้วยเช่นกัน - The strict equality operator `===` doesn't do the conversion: different types always mean different values for it. + ตัวดำเนินการเปรียบเทียบความเท่ากันแบบเข้มงวด `===` จะไม่แปลงค่า: ชนิดที่ต่างกันเสมอไปจะถือว่าค่าไม่เท่ากัน - Values `null` and `undefined` are special: they equal `==` each other and don't equal anything else. + ค่า `null` และ `undefined` เป็นพิเศษ: พวกมันเท่ากับ `==` กันเองและไม่เท่ากับอะไรอื่น - Greater/less comparisons compare strings character-by-character, other types are converted to a number. + การเปรียบเทียบมากกว่า/น้อยกว่าจะเปรียบเทียบสตริงทีละอักขระ ส่วนชนิดอื่นจะแปลงเป็นตัวเลข -Other operators -: There are few others, like a comma operator. +ตัวดำเนินการอื่นๆ +: มีอีกไม่กี่ตัว เช่น comma operator -More in: , , , . +อ่านเพิ่มเติมได้ที่: , , , -## Loops +## ลูป -- We covered 3 types of loops: +- เราได้ครอบคลุมลูป 3 ประเภท: ```js // 1 @@ -197,25 +216,25 @@ More in: , , , . +รายละเอียดใน: -Later we'll study more types of loops to deal with objects. +ในภายหลังเราจะศึกษาลูปชนิดอื่นๆ เพิ่มเติมเพื่อจัดการกับออบเจ็กต์ -## The "switch" construct +## โครงสร้าง "switch" -The "switch" construct can replace multiple `if` checks. It uses `===` (strict equality) for comparisons. +โครงสร้าง "switch" สามารถใช้แทนการตรวจสอบ `if` หลายครั้งได้ มันใช้ `===` (ตรวจสอบความเท่ากันแบบเข้มงวด) ในการเปรียบเทียบ -For instance: +ตัวอย่างเช่น: ```js run let age = prompt('Your age?', 18); switch (age) { case 18: - alert("Won't work"); // the result of prompt is a string, not a number + alert("Won't work"); // ผลลัพธ์จาก prompt เป็นสตริง ไม่ใช่ตัวเลข break; case "18": @@ -227,13 +246,13 @@ switch (age) { } ``` -Details in: . +รายละเอียดใน: -## Functions +## ฟังก์ชัน -We covered three ways to create a function in JavaScript: +เราได้ครอบคลุมวิธีการสร้างฟังก์ชันใน JavaScript สามแบบ: -1. Function Declaration: the function in the main code flow +1. Function Declaration: ฟังก์ชันในลำดับการทำงานหลักของโค้ด ```js function sum(a, b) { @@ -243,7 +262,7 @@ We covered three ways to create a function in JavaScript: } ``` -2. Function Expression: the function in the context of an expression +2. Function Expression: ฟังก์ชันในบริบทของนิพจน์ ```js let sum = function(a, b) { @@ -256,29 +275,32 @@ We covered three ways to create a function in JavaScript: 3. Arrow functions: ```js +<<<<<<< HEAD + // นิพจน์ทางด้านขวา +======= // expression on the right side +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 let sum = (a, b) => a + b; - // or multi-line syntax with { ... }, need return here: + // หรือใช้ไวยากรณ์แบบหลายบรรทัดด้วย { ... }, ต้องใส่ return ที่นี่: let sum = (a, b) => { // ... return a + b; } - // without arguments + // ไม่มีอาร์กิวเมนต์ let sayHi = () => alert("Hello"); - // with a single argument + // มีอาร์กิวเมนต์เดียว let double = n => n * 2; ``` +- ฟังก์ชันอาจมีตัวแปรภายใน (local variables): คือตัวแปรที่ประกาศภายในบอดี้หรือในรายการพารามิเตอร์ของมัน ตัวแปรเหล่านี้จะมองเห็นได้เฉพาะภายในฟังก์ชัน +- พารามิเตอร์สามารถกำหนดค่าเริ่มต้นได้: `function sum(a = 1, b = 2) {...}` +- ฟังก์ชันจะคืนค่าอะไรบางอย่างเสมอ หากไม่มีประโยค `return` ผลลัพธ์จะเป็น `undefined` -- Functions may have local variables: those declared inside its body or its parameter list. Such variables are only visible inside the function. -- Parameters can have default values: `function sum(a = 1, b = 2) {...}`. -- Functions always return something. If there's no `return` statement, then the result is `undefined`. - -Details: see , . +รายละเอียด: ดูที่ , -## More to come +## ในอนาคตยังมีอีกมาก -That was a brief list of JavaScript features. As of now we've studied only basics. Further in the tutorial you'll find more specials and advanced features of JavaScript. +นี่เป็นเพียงรายการโดยย่อของคุณลักษณะต่างๆ ของ JavaScript ณ ตอนนี้เราได้ศึกษาเฉพาะพื้นฐานเท่านั้น ในบทเรียนต่อๆ ไปคุณจะได้เจอกับคุณสมบัติพิเศษและขั้นสูงของ JavaScript เพิ่มเติม \ No newline at end of file diff --git a/1-js/02-first-steps/index.md b/1-js/02-first-steps/index.md index 31281656f..614444a00 100644 --- a/1-js/02-first-steps/index.md +++ b/1-js/02-first-steps/index.md @@ -1,3 +1,3 @@ -# JavaScript Fundamentals +# พื้นฐานจาวาสคริปต์ -Let's learn the fundamentals of script building. \ No newline at end of file +มาเริ่มเรียนรู้การเขียนจาวาสคริปต์กัน diff --git a/1-js/03-code-quality/01-debugging-chrome/article.md b/1-js/03-code-quality/01-debugging-chrome/article.md index 4f50fb428..91aaaeae3 100644 --- a/1-js/03-code-quality/01-debugging-chrome/article.md +++ b/1-js/03-code-quality/01-debugging-chrome/article.md @@ -1,195 +1,279 @@ -# Debugging in the browser +# การดีบักใน Browser -Before writing more complex code, let's talk about debugging. +ก่อนที่เราจะเขียนโค้ดที่ซับซ้อนกว่านี้ มาคุยกันเรื่องการดีบักกันสักหน่อย -[Debugging](https://en.wikipedia.org/wiki/Debugging) is the process of finding and fixing errors within a script. All modern browsers and most other environments support debugging tools -- a special UI in developer tools that makes debugging much easier. It also allows to trace the code step by step to see what exactly is going on. +[Debugging](https://en.wikipedia.org/wiki/Debugging) คือกระบวนการค้นหาและแก้ไขข้อผิดพลาดภายในสคริปต์ เบราว์เซอร์สมัยใหม่ทั้งหมดและสภาพแวดล้อมส่วนใหญ่รองรับเครื่องมือสำหรับดีบัก -- พวก UI พิเศษในเครื่องมือนักพัฒนาที่ช่วยให้การดีบักง่ายขึ้นมาก นอกจากนี้ยังช่วยให้สามารถติดตามการทำงานของโค้ดได้ทีละขั้นตอน เพื่อดูว่าเกิดอะไรขึ้นกันแน่ -We'll be using Chrome here, because it has enough features, most other browsers have a similar process. +เราจะใช้ Chrome ที่นี่เพราะมันมีฟีเจอร์ที่เพียงพอ ส่วนเบราว์เซอร์อื่นๆ ส่วนใหญ่ก็มีขั้นตอนคล้ายๆ กัน -## The "Sources" panel +## แผง "Sources" -Your Chrome version may look a little bit different, but it still should be obvious what's there. +Chrome เวอร์ชันที่คุณใช้อาจมีหน้าตาแตกต่างกันไปเล็กน้อย แต่ก็น่าจะเห็นได้ชัดเจนว่ามีอะไรอยู่ที่นั่นบ้าง -- Open the [example page](debugging/index.html) in Chrome. -- Turn on developer tools with `key:F12` (Mac: `key:Cmd+Opt+I`). -- Select the `Sources` panel. +- เปิด[หน้าตัวอย่าง](debugging/index.html) ใน Chrome +- เปิดเครื่องมือนักพัฒนาด้วย `key:F12` (Mac: `key:Cmd+Opt+I`) +- เลือกแผง `Sources` -Here's what you should see if you are doing it for the first time: +นี่คือสิ่งที่คุณควรเห็น ถ้าเป็นครั้งแรกที่ทำ: ![](chrome-open-sources.svg) -The toggler button opens the tab with files. +ปุ่มสลับ จะเปิดแท็บที่มีไฟล์ต่างๆ -Let's click it and select `hello.js` in the tree view. Here's what should show up: +ลองคลิกที่มันแล้วเลือก `hello.js` ในมุมมองแบบต้นไม้ นี่คือสิ่งที่น่าจะปรากฏขึ้น: ![](chrome-tabs.svg) -The Sources panel has 3 parts: +แผง Sources ประกอบด้วย 3 ส่วน: -1. The **File Navigator** pane lists HTML, JavaScript, CSS and other files, including images that are attached to the page. Chrome extensions may appear here too. -2. The **Code Editor** pane shows the source code. -3. The **JavaScript Debugging** pane is for debugging, we'll explore it soon. +1. บานหน้าต่าง **File Navigator** จะแสดงรายการไฟล์ HTML, JavaScript, CSS และอื่นๆ รวมถึงรูปภาพที่แนบมากับหน้าเว็บด้วย ส่วนขยายของ Chrome ก็อาจปรากฏที่นี่เช่นกัน +2. บานหน้าต่าง **Code Editor** จะแสดงซอร์สโค้ด +3. บานหน้าต่าง **JavaScript Debugging** ใช้สำหรับดีบัก เราจะมาดูมันกันในอีกสักครู่ -Now you could click the same toggler again to hide the resources list and give the code some space. +ตอนนี้คุณสามารถคลิกที่ปุ่มสลับ อีกครั้งเพื่อซ่อนรายการทรัพยากรและเพิ่มพื้นที่ให้กับส่วนแสดงโค้ด ## Console -If we press `key:Esc`, then a console opens below. We can type commands there and press `key:Enter` to execute. +หากเรากด `key:Esc` คอนโซลจะเปิดขึ้นมาด้านล่าง เราสามารถพิมพ์คำสั่งลงไปที่นั่นแล้วกด `key:Enter` เพื่อให้มันทำงาน -After a statement is executed, its result is shown below. +หลังจากคำสั่งถูกประมวลผลแล้ว ผลลัพธ์ก็จะแสดงอยู่ด้านล่าง +<<<<<<< HEAD +ตัวอย่างเช่น ในที่นี้ `1+2` ให้ผลลัพธ์เป็น `3` ในขณะที่การเรียก function `hello("debugger")` ไม่ได้ส่งค่าใดๆ กลับมา ดังนั้นผลลัพธ์ที่ได้คือ `undefined`: +======= For example, here `1+2` results in `3`, while the function call `hello("debugger")` returns nothing, so the result is `undefined`: +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ![](chrome-sources-console.svg) ## Breakpoints -Let's examine what's going on within the code of the [example page](debugging/index.html). In `hello.js`, click at line number `4`. Yes, right on the `4` digit, not on the code. +มาดูกันว่ามีอะไรเกิดขึ้นในโค้ดของ[หน้าตัวอย่าง](debugging/index.html) บ้าง ใน `hello.js` ให้คลิกที่เลขบรรทัดที่ `4` ใช่ คลิกที่ตัวเลข `4` เลย ไม่ใช่ที่โค้ด -Congratulations! You've set a breakpoint. Please also click on the number for line `8`. +ยินดีด้วย! คุณได้ตั้ง breakpoint แล้ว กรุณาคลิกที่เลขบรรทัดที่ `8` ด้วย -It should look like this (blue is where you should click): +มันควรจะมีหน้าตาแบบนี้ (สีน้ำเงินคือตำแหน่งที่คุณควรคลิก): ![](chrome-sources-breakpoint.svg) -A *breakpoint* is a point of code where the debugger will automatically pause the JavaScript execution. +*breakpoint* คือจุดในโค้ดที่ตัวดีบักเกอร์จะหยุดการทำงานของ JavaScript โดยอัตโนมัติ -While the code is paused, we can examine current variables, execute commands in the console etc. In other words, we can debug it. +ในขณะที่โค้ดหยุดอยู่ เราสามารถตรวจสอบค่าตัวแปรในปัจจุบัน รันคำสั่งในคอนโซล หรือทำอย่างอื่นได้ หรือพูดอีกอย่างคือ เราสามารถดีบักโค้ดตรงนั้นได้ -We can always find a list of breakpoints in the right panel. That's useful when we have many breakpoints in various files. It allows us to: -- Quickly jump to the breakpoint in the code (by clicking on it in the right panel). -- Temporarily disable the breakpoint by unchecking it. -- Remove the breakpoint by right-clicking and selecting Remove. -- ...And so on. +เราสามารถดูรายการ breakpoint ทั้งหมดได้ที่แผงด้านขวาเสมอ ซึ่งมีประโยชน์มากเวลาเรามี breakpoint หลายจุดในหลายๆ ไฟล์ มันช่วยให้เรา: +- ข้ามไปยัง breakpoint ในโค้ดได้อย่างรวดเร็ว (โดยคลิกที่มันในแผงด้านขวา) +- ปิดการทำงานของ breakpoint ชั่วคราวโดยการเอาเครื่องหมายถูกออก +- ลบ breakpoint โดยคลิกขวาแล้วเลือก Remove +- ...และอื่นๆ ```smart header="Conditional breakpoints" +<<<<<<< HEAD +การ *คลิกขวา* บนเลขบรรทัดจะช่วยให้สร้าง breakpoint *แบบมีเงื่อนไข* ได้ มันจะทำงานก็ต่อเมื่อนิพจน์ที่กำหนดไว้ตอนสร้าง (ซึ่งคุณต้องใส่เอง) มีค่าเป็นจริงเท่านั้น +======= *Right click* on the line number allows to create a *conditional* breakpoint. It only triggers when the given expression, that you should provide when you create it, is truthy. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -That's handy when we need to stop only for a certain variable value or for certain function parameters. +นี่เป็นประโยชน์มากเวลาที่เราอยากจะหยุดเฉพาะตอนที่ค่าตัวแปรบางตัว หรือพารามิเตอร์ของฟังก์ชันบางตัวมีค่าตามที่ระบุไว้เท่านั้น ``` +<<<<<<< HEAD +## คำสั่ง "debugger" +======= ## The command "debugger" +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -We can also pause the code by using the `debugger` command in it, like this: +นอกจากนี้เรายังสามารถหยุดการทำงานของโค้ดได้โดยใช้คำสั่ง `debugger` ในโค้ดโดยตรง แบบนี้: ```js function hello(name) { let phrase = `Hello, ${name}!`; *!* - debugger; // <-- the debugger stops here + debugger; // <-- ตัวดีบักเกอร์จะหยุดที่ตรงนี้ */!* say(phrase); } ``` +<<<<<<< HEAD +คำสั่งลักษณะนี้จะทำงานก็ต่อเมื่อเครื่องมือนักพัฒนากำลังเปิดอยู่เท่านั้น ไม่เช่นนั้นเบราว์เซอร์จะข้ามมันไป + +## จุดหยุด (Breakpoints) +======= Such command works only when the development tools are open, otherwise the browser ignores it. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +มาดูกันว่ามีอะไรเกิดขึ้นในโค้ดของ [example page](debugging/index.html) บ้าง ใน `hello.js` ให้คลิกที่เลขบรรทัดที่ `4` ใช่ คลิกที่ตัวเลข `4` เลย ไม่ใช่ที่โค้ด + +ยินดีด้วย! คุณได้ตั้ง breakpoint แล้ว กรุณาคลิกที่เลขบรรทัดที่ `8` ด้วย + +มันควรจะมีหน้าตาแบบนี้ (สีน้ำเงินคือตำแหน่งที่คุณควรคลิก): + +![](chrome-sources-breakpoint.svg) + +*breakpoint* คือจุดในโค้ดที่ตัวดีบักเกอร์จะหยุดการทำงานของ JavaScript โดยอัตโนมัติ + +ในขณะที่โค้ดหยุดอยู่ เราสามารถตรวจสอบค่าตัวแปรในปัจจุบัน รันคำสั่งในคอนโซล หรือทำอย่างอื่นได้ หรือพูดอีกอย่างคือ เราสามารถดีบักโค้ดตรงนั้นได้ + +เราสามารถดูรายการ breakpoint ทั้งหมดได้ที่แผงด้านขวาเสมอ ซึ่งมีประโยชน์มากเวลาเรามี breakpoint หลายจุดในหลายๆ ไฟล์ มันช่วยให้เรา: +- ข้ามไปยัง breakpoint ในโค้ดได้อย่างรวดเร็ว (โดยคลิกที่มันในแผงด้านขวา) +- ปิดการทำงานของ breakpoint ชั่วคราวโดยการเอาเครื่องหมายถูกออก +- ลบ breakpoint โดยคลิกขวาแล้วเลือก Remove +- ...และอื่นๆ + +```smart header="Conditional breakpoints" +การ *คลิกขวา* บนเลขบรรทัดจะช่วยให้สร้าง breakpoint *แบบมีเงื่อนไข* ได้ มันจะทำงานก็ต่อเมื่อนิพจน์ที่กำหนดไว้ตอนสร้าง (ซึ่งคุณต้องใส่เอง) มีค่าเป็นจริงเท่านั้น + +นี่เป็นประโยชน์มากเวลาที่เราอยากจะหยุดเฉพาะตอนที่ค่าตัวแปรบางตัว หรือพารามิเตอร์ของฟังก์ชันบางตัวมีค่าตามที่ระบุไว้เท่านั้น +``` + +## คำสั่ง "debugger" + +นอกจากนี้เรายังสามารถหยุดการทำงานของโค้ดได้โดยใช้คำสั่ง `debugger` ในโค้ดโดยตรง แบบนี้: -## Pause and look around +```js +function hello(name) { + let phrase = `Hello, ${name}!`; -In our example, `hello()` is called during the page load, so the easiest way to activate the debugger (after we've set the breakpoints) is to reload the page. So let's press `key:F5` (Windows, Linux) or `key:Cmd+R` (Mac). +*!* + debugger; // <-- ตัวดีบักเกอร์จะหยุดที่ตรงนี้ +*/!* -As the breakpoint is set, the execution pauses at the 4th line: + say(phrase); +} +``` + +คำสั่งลักษณะนี้จะทำงานก็ต่อเมื่อเครื่องมือนักพัฒนากำลังเปิดอยู่เท่านั้น ไม่เช่นนั้นเบราว์เซอร์จะข้ามมันไป + +## หยุดแล้วสำรวจดูรอบๆ + +ในตัวอย่างของเรา `hello()` ถูกเรียกใช้ระหว่างการโหลดหน้าเว็บ ดังนั้นวิธีที่ง่ายที่สุดในการเปิดใช้งานตัวดีบักเกอร์ (หลังจากตั้ง breakpoint แล้ว) คือการโหลดหน้าเว็บใหม่ ดังนั้นมากดปุ่ม `key:F5` (Windows, Linux) หรือ `key:Cmd+R` (Mac) กัน + +เนื่องจากมีการตั้ง breakpoint ไว้ การทำงานของโปรแกรมจะหยุดที่บรรทัดที่ 4: ![](chrome-sources-debugger-pause.svg) -Please open the informational dropdowns to the right (labeled with arrows). They allow you to examine the current code state: +กรุณาเปิดดรอปดาวน์ที่แสดงข้อมูลด้านขวา (ที่มีลูกศรชี้อยู่) มันจะช่วยให้คุณสามารถตรวจสอบสถานะของโค้ดในปัจจุบันได้: -1. **`Watch` -- shows current values for any expressions.** +1. **`Watch` -- แสดงค่าปัจจุบันของนิพจน์ต่างๆ** +<<<<<<< HEAD + คุณสามารถคลิกที่เครื่องหมายบวก `+` แล้วใส่นิพจน์เข้าไป ตัวดีบักเกอร์จะแสดงค่าของนิพจน์นั้น โดยจะคำนวณใหม่โดยอัตโนมัติในระหว่างการประมวลผล +======= You can click the plus `+` and input an expression. The debugger will show its value, automatically recalculating it in the process of execution. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -2. **`Call Stack` -- shows the nested calls chain.** +2. **`Call Stack` -- แสดงลำดับการเรียกฟังก์ชันที่ซ้อนกัน** - At the current moment the debugger is inside `hello()` call, called by a script in `index.html` (no function there, so it's called "anonymous"). + ในตอนนี้ตัวดีบักเกอร์กำลังอยู่ในการเรียกฟังก์ชัน `hello()` ซึ่งถูกเรียกโดยสคริปต์ใน `index.html` (ไม่มีฟังก์ชันที่นั่น จึงเรียกว่า "anonymous") - If you click on a stack item (e.g. "anonymous"), the debugger jumps to the corresponding code, and all its variables can be examined as well. -3. **`Scope` -- current variables.** + ถ้าคุณคลิกที่รายการใน call stack (เช่น "anonymous") ตัวดีบักเกอร์จะข้ามไปยังโค้ดส่วนนั้น และคุณก็สามารถตรวจสอบค่าตัวแปรทั้งหมดที่นั่นได้เช่นกัน +3. **`Scope` -- ตัวแปรในขอบเขตปัจจุบัน** - `Local` shows local function variables. You can also see their values highlighted right over the source. + `Local` จะแสดงตัวแปรภายในในฟังก์ชัน คุณจะเห็นค่าของพวกมันถูกไฮไลต์อยู่เหนือโค้ดด้วย - `Global` has global variables (out of any functions). + `Global` จะแสดงตัวแปรระดับโกลบอล (ที่อยู่นอกฟังก์ชันใดๆ) - There's also `this` keyword there that we didn't study yet, but we'll do that soon. + นอกจากนี้ยังมีคีย์เวิร์ด `this` ที่เรายังไม่ได้ศึกษา แต่เราจะได้เรียนรู้เร็วๆ นี้แหละ -## Tracing the execution +## การติดตามการประมวลผล -Now it's time to *trace* the script. +ตอนนี้ถึงเวลา *ติดตาม* การทำงานของสคริปต์แล้ว -There are buttons for it at the top of the right panel. Let's engage them. +มีปุ่มสำหรับการติดตามอยู่ที่ด้านบนของแผงด้านขวา มาลองใช้กันเลย - -- "Resume": continue the execution, hotkey `key:F8`. -: Resumes the execution. If there are no additional breakpoints, then the execution just continues and the debugger loses control. + -- "Resume": ดำเนินการประมวลผลต่อ, ปุ่มลัด `key:F8` +: ดำเนินการประมวลผลโค้ดต่อไป ถ้าไม่มี breakpoint เพิ่มเติม การประมวลผลจะดำเนินต่อเรื่อยๆ และตัวดีบักเกอร์จะหยุดควบคุมการทำงาน - Here's what we can see after a click on it: + นี่คือสิ่งที่เราจะเห็นหลังจากคลิกที่ปุ่มนี้: ![](chrome-sources-debugger-trace-1.svg) - The execution has resumed, reached another breakpoint inside `say()` and paused there. Take a look at the "Call Stack" at the right. It has increased by one more call. We're inside `say()` now. + การประมวลผลได้ดำเนินต่อไปแล้ว ไปถึง breakpoint อีกจุดหนึ่งภายในฟังก์ชัน `say()` และหยุดอยู่ที่นั่น ลองดูที่ "Call Stack" ทางด้านขวา จะเห็นว่ามีการเรียกเพิ่มขึ้นมาอีกหนึ่งชั้น ตอนนี้เรากำลังอยู่ภายในฟังก์ชัน `say()` - -- "Step": run the next command, hotkey `key:F9`. -: Run the next statement. If we click it now, `alert` will be shown. + -- "Step": ดำเนินคำสั่งถัดไป, ปุ่มลัด `key:F9` +: ดำเนินการตามคำสั่งถัดไป ถ้าเราคลิกตอนนี้ จะมี `alert` ปรากฏขึ้น - Clicking this again and again will step through all script statements one by one. + คลิกแบบนี้ซ้ำๆ จะทำให้ผ่านคำสั่งต่างๆ ในสคริปต์ไปทีละคำสั่ง +<<<<<<< HEAD + -- "Step over": ดำเนินคำสั่งถัดไป แต่ *ไม่ต้องเข้าไปในฟังก์ชัน*, ปุ่มลัด `key:F10` +: คล้ายกับคำสั่ง "Step" ก่อนหน้า แต่จะทำงานแตกต่างกันถ้าคำสั่งถัดไปเป็นการเรียกฟังก์ชัน (ไม่ใช่ฟังก์ชันในตัว เช่น `alert` แต่เป็นฟังก์ชันที่เราสร้างเอง) + + ถ้าเปรียบเทียบกัน คำสั่ง "Step" จะเข้าไปในการเรียกฟังก์ชันซ้อน และหยุดการประมวลผลที่บรรทัดแรกของฟังก์ชันนั้น แต่ "Step over" จะประมวลผลการเรียกฟังก์ชันซ้อนโดยที่เราไม่เห็น ข้ามการทำงานภายในฟังก์ชันไป + + จากนั้นการประมวลผลจะหยุดทันทีหลังจบการเรียกฟังก์ชันนั้น +======= -- "Step over": run the next command, but *don't go into a function*, hotkey `key:F10`. : Similar to the previous "Step" command, but behaves differently if the next statement is a function call (not a built-in, like `alert`, but a function of our own). If we compare them, the "Step" command goes into a nested function call and pauses the execution at its first line, while "Step over" executes the nested function call invisibly to us, skipping the function internals. The execution is then paused immediately after that function call. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 - That's good if we're not interested to see what happens inside the function call. + นี่จะมีประโยชน์ถ้าเราไม่สนใจที่จะดูว่ามีอะไรเกิดขึ้นภายในฟังก์ชันนั้นบ้าง - -- "Step into", hotkey `key:F11`. -: That's similar to "Step", but behaves differently in case of asynchronous function calls. If you're only starting to learn JavaScript, then you can ignore the difference, as we don't have asynchronous calls yet. + -- "Step into", ปุ่มลัด `key:F11` +: คล้ายกับ "Step" แต่จะทำงานต่างกันกรณีการเรียกฟังก์ชันแบบอะซิงโครนัส ถ้าคุณเพิ่งเริ่มเรียน JavaScript คุณสามารถข้ามส่วนนี้ไปก่อนได้ เพราะเรายังไม่มีการเรียกแบบอะซิงโครนัส - For the future, just note that "Step" command ignores async actions, such as `setTimeout` (scheduled function call), that execute later. The "Step into" goes into their code, waiting for them if necessary. See [DevTools manual](https://developers.google.com/web/updates/2018/01/devtools#async) for more details. + แค่จำไว้ว่าคำสั่ง "Step" จะข้ามการทำงานแบบ async เช่น `setTimeout` (การเรียกฟังก์ชันตามเวลาที่กำหนด) ที่จะประมวลผลภายหลัง ส่วน "Step into" จะเข้าไปในโค้ดส่วนนั้น รอจนกว่ามันจะเสร็จถ้าจำเป็น อ่านรายละเอียดเพิ่มเติมได้ใน [คู่มือ DevTools](https://developers.google.com/web/updates/2018/01/devtools#async) - -- "Step out": continue the execution till the end of the current function, hotkey `key:Shift+F11`. -: Continue the execution and stop it at the very last line of the current function. That's handy when we accidentally entered a nested call using , but it does not interest us, and we want to continue to its end as soon as possible. + -- "Step out": ดำเนินการประมวลผลต่อจนจบฟังก์ชันปัจจุบัน, ปุ่มลัด `key:Shift+F11` +: ดำเนินการประมวลผลโค้ดต่อไปจนถึงบรรทัดสุดท้ายของฟังก์ชันปัจจุบัน ใช้เมื่อเราเข้าไปในฟังก์ชันซ้อนโดยไม่ได้ตั้งใจโดยใช้ แต่ไม่ได้สนใจการทำงานในนั้น และอยากให้มันจบโดยเร็ว - -- enable/disable all breakpoints. -: That button does not move the execution. Just a mass on/off for breakpoints. + -- เปิด/ปิดใช้งาน breakpoint ทั้งหมด +: ปุ่มนี้ไม่ได้เลื่อนการประมวลผล แต่เป็นการเปิด/ปิด breakpoint ทั้งหมดพร้อมกัน +<<<<<<< HEAD + -- เปิด/ปิดการหยุดอัตโนมัติเมื่อมีข้อผิดพลาด +: เมื่อเปิดใช้งาน หากเครื่องมือนักพัฒนากำลังเปิดอยู่ เวลามีข้อผิดพลาดเกิดขึ้นระหว่างการประมวลผลสคริปต์ มันจะหยุดทำงานทันที ซึ่งเราสามารถใช้ตรวจสอบค่าตัวแปรต่างๆ ในตัวดีบักเกอร์เพื่อดูว่ามีอะไรผิดปกติ ดังนั้นถ้าสคริปต์ของเราหยุดการทำงานเพราะข้อผิดพลาด เราสามารถเปิดตัวดีบักเกอร์ เปิดใช้งานตัวเลือกนี้ แล้วโหลดหน้าเว็บใหม่เพื่อดูว่ามันหยุดที่ตรงไหน และสถานะตอนนั้นเป็นยังไง +======= -- enable/disable automatic pause in case of an error. : When enabled, if the developer tools is open, an error during the script execution automatically pauses it. Then we can analyze variables in the debugger to see what went wrong. So if our script dies with an error, we can open debugger, enable this option and reload the page to see where it dies and what's the context at that moment. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 ```smart header="Continue to here" -Right click on a line of code opens the context menu with a great option called "Continue to here". +คลิกขวาที่บรรทัดโค้ดจะเปิดเมนูบริบท ซึ่งมีตัวเลือกที่ดีมากอย่าง "Continue to here" -That's handy when we want to move multiple steps forward to the line, but we're too lazy to set a breakpoint. +นี่จะมีประโยชน์เมื่อเราอยากข้ามไปหลายขั้นตอนจนถึงบรรทัดนั้น แต่ขี้เกียจตั้ง breakpoint ``` -## Logging +## การเก็บล็อก -To output something to console from our code, there's `console.log` function. +เพื่อแสดงผลบางอย่างไปยังคอนโซลจากโค้ดของเรา เราสามารถใช้ฟังก์ชัน `console.log` -For instance, this outputs values from `0` to `4` to console: +ตัวอย่างเช่น โค้ดนี้จะแสดงค่าตั้งแต่ `0` ถึง `4` ไปที่คอนโซล: ```js run -// open console to see +// เปิดคอนโซลเพื่อดูผลลัพธ์ for (let i = 0; i < 5; i++) { console.log("value,", i); } ``` -Regular users don't see that output, it is in the console. To see it, either open the Console panel of developer tools or press `key:Esc` while in another panel: that opens the console at the bottom. +ผู้ใช้ทั่วไปจะไม่เห็นผลลัพธ์นี้ เพราะมันอยู่ในคอนโซล หากต้องการดู ให้เปิดแผง Console ในเครื่องมือสำหรับนักพัฒนา หรือกด `key:Esc` ในขณะที่อยู่ในแผงอื่น ซึ่งจะเปิดคอนโซลขึ้นมาที่ด้านล่างของหน้าจอ -If we have enough logging in our code, then we can see what's going on from the records, without the debugger. +ถ้าเรามีการล็อกในโค้ดมากพอ เราจะสามารถติดตามได้ว่ากำลังเกิดอะไรขึ้นจากข้อมูลที่ถูกบันทึกไว้ โดยไม่จำเป็นต้องใช้ตัวดีบักเกอร์ -## Summary +ข้อความสรุปนี้อธิบายวิธีการหยุดการทำงานของสคริปต์และการใช้งานเครื่องมือนักพัฒนาได้ดีมากครับ ภาษาที่ใช้ก็ชัดเจนเข้าใจง่าย -As we can see, there are three main ways to pause a script: -1. A breakpoint. -2. The `debugger` statements. -3. An error (if dev tools are open and the button is "on"). +## สรุป +<<<<<<< HEAD +อย่างที่เราเห็น มีสามวิธีหลักในการหยุดการทำงานของสคริปต์: +1. จุดหยุด (breakpoint) +2. คำสั่ง `debugger` +3. ข้อผิดพลาด (ถ้าเครื่องมือนักพัฒนากำลังเปิดอยู่และปุ่ม อยู่ในสถานะ "เปิด") +======= When paused, we can debug: examine variables and trace the code to see where the execution goes wrong. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 + +เมื่อหยุดแล้ว เราสามารถดีบักได้โดยการตรวจสอบค่าตัวแปรและติดตามการทำงานของโค้ด เพื่อดูว่าการประมวลผลผิดพลาดตรงจุดไหน -There are many more options in developer tools than covered here. The full manual is at . +เครื่องมือนักพัฒนามีตัวเลือกอีกมากมายนอกเหนือจากที่กล่าวถึงที่นี่ สามารถอ่านคู่มือฉบับเต็มได้ที่ -The information from this chapter is enough to begin debugging, but later, especially if you do a lot of browser stuff, please go there and look through more advanced capabilities of developer tools. +ข้อมูลในบทความนี้เพียงพอสำหรับการเริ่มต้นดีบัก แต่ในภายหลัง โดยเฉพาะถ้าคุณต้องทำงานกับเบราว์เซอร์บ่อยๆ แนะนำให้ไปศึกษาเพิ่มเติมเกี่ยวกับความสามารถขั้นสูงของเครื่องมือนักพัฒนา -Oh, and also you can click at various places of dev tools and just see what's showing up. That's probably the fastest route to learn dev tools. Don't forget about the right click and context menus! +อ้อ แล้วก็คุณสามารถคลิกที่ส่วนต่างๆ ของเครื่องมือนักพัฒนา แล้วสังเกตดูว่ามีอะไรปรากฏขึ้นบ้าง นี่น่าจะเป็นวิธีที่เร็วที่สุดในการเรียนรู้การใช้งานเครื่องมือนักพัฒนา และอย่าลืมลองคลิกขวาเพื่อเปิดเมนูบริบทดูด้วยล่ะ! \ No newline at end of file diff --git a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md index 4facc8b29..11f43159a 100644 --- a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md +++ b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md @@ -1,29 +1,29 @@ -You could note the following: +คุณสามารถจดบันทึกต่อไปนี้ได้: ```js no-beautify -function pow(x,n) // <- no space between arguments -{ // <- figure bracket on a separate line - let result=1; // <- no spaces before or after = - for(let i=0;i -Now let's discuss the rules and reasons for them in detail. +ทีนี้มาคุยถึงกฎและเหตุผลของกฎเหล่านี้อย่างละเอียดกันดีกว่า -```warn header="There are no \"you must\" rules" -Nothing is set in stone here. These are style preferences, not religious dogmas. +```warn header="ไม่มีกฎ \"ต้องทำ\" ตายตัว" +ไม่มีอะไรที่ตายตัวที่นี่ ข้อเสนอแนะเหล่านี้เป็นแค่รสนิยมในการจัดรูปแบบโค้ด ไม่ใช่หลักคำสอนทางศาสนา ``` -### Curly Braces +### วงเล็บปีกกา -In most JavaScript projects curly braces are written in "Egyptian" style with the opening brace on the same line as the corresponding keyword -- not on a new line. There should also be a space before the opening bracket, like this: +ในโปรเจ็กต์ JavaScript ส่วนใหญ่ วงเล็บปีกกาจะเขียนในสไตล์ "อียิปต์" โดยวงเปิดจะอยู่บรรทัดเดียวกันกับคีย์เวิร์ดที่เกี่ยวข้อง -- ไม่ใช่บรรทัดใหม่ และควรมีช่องว่างก่อนวงเปิดด้วย แบบนี้: ```js if (condition) { - // do this - // ...and that - // ...and that + // ทำอันนี้ + // ...แล้วก็อันนั้น + // ...แล้วก็อันนู่น } ``` -A single-line construct, such as `if (condition) doSomething()`, is an important edge case. Should we use braces at all? - -Here are the annotated variants so you can judge their readability for yourself: - -1. 😠 Beginners sometimes do that. Bad! Curly braces are not needed: - ```js - if (n < 0) *!*{*/!*alert(`Power ${n} is not supported`);*!*}*/!* - ``` -2. 😠 Split to a separate line without braces. Never do that, easy to make an error when adding new lines: - ```js - if (n < 0) - alert(`Power ${n} is not supported`); - ``` -3. 😏 One line without braces - acceptable, if it's short: - ```js - if (n < 0) alert(`Power ${n} is not supported`); - ``` -4. 😃 The best variant: - ```js - if (n < 0) { - alert(`Power ${n} is not supported`); - } - ``` - -For a very brief code, one line is allowed, e.g. `if (cond) return null`. But a code block (the last variant) is usually more readable. - -### Line Length - -No one likes to read a long horizontal line of code. It's best practice to split them. - -For example: +กรณีพิเศษที่สำคัญคือประโยคบรรทัดเดียว เช่น `if (condition) doSomething()` เราควรใช้วงเล็บปีกกาหรือไม่? + +ต่อไปนี้คือตัวเลือกพร้อมคำอธิบาย เพื่อให้คุณตัดสินความสามารถในการอ่านทำความเข้าใจด้วยตัวเอง: + +1. 😠 มือใหม่บางคนทำแบบนี้ ไม่ดีเลย! ไม่จำเป็นต้องใช้วงเล็บปีกกา: + ```js + if (n < 0) *!*{*/!*alert(`เลขยกกำลัง ${n} ไม่รองรับ`);*!*}*/!* + ``` +2. 😠 แยกเป็นบรรทัดใหม่โดยไม่ใช้วงเล็บปีกกา อย่าทำแบบนี้เลย เพราะจะผิดพลาดง่ายเวลาเพิ่มบรรทัดใหม่: + ```js + if (n < 0) + alert(`เลขยกกำลัง ${n} ไม่รองรับ`); + ``` +3. 😏 เขียนบรรทัดเดียวโดยไม่ใช้วงเล็บปีกกา - ยอมรับได้ถ้าสั้น: + ```js + if (n < 0) alert(`เลขยกกำลัง ${n} ไม่รองรับ`); + ``` +4. 😃 ตัวเลือกที่ดีที่สุด: + ```js + if (n < 0) { + alert(`เลขยกกำลัง ${n} ไม่รองรับ`); + } + ``` + +สำหรับโค้ดที่สั้นมากๆ อนุญาตให้เขียนบรรทัดเดียวได้ เช่น `if (cond) return null` แต่โดยทั่วไปแล้วการเขียนเป็นบล็อกโค้ด (ตัวเลือกสุดท้าย) จะอ่านเข้าใจง่ายกว่า + +### ความยาวบรรทัด + +ไม่มีใครชอบอ่านบรรทัดโค้ดยาวๆ ในแนวนอน ถือเป็นแนวปฏิบัติที่ดีที่จะตัดแบ่งบรรทัดพวกนั้น + +ยกตัวอย่างเช่น: ```js -// backtick quotes ` allow to split the string into multiple lines +// เครื่องหมาย backtick ` ทำให้แบ่งสตริงเป็นหลายบรรทัดได้ let str = ` - ECMA International's TC39 is a group of JavaScript developers, - implementers, academics, and more, collaborating with the community - to maintain and evolve the definition of JavaScript. + ECMA International's TC39 เป็นกลุ่มนักพัฒนา JavaScript, + ผู้ทำระบบ, นักวิชาการ และอีกมากมาย ที่ร่วมกันดูแลรักษากับชุมชน + เพื่อปรับปรุงและพัฒนานิยามของ JavaScript `; ``` -And, for `if` statements: +และสำหรับประโยค `if`: ```js if ( id === 123 && - moonPhase === 'Waning Gibbous' && + moonPhase === 'Waning Gibbous' && zodiacSign === 'Libra' ) { letTheSorceryBegin(); } ``` -The maximum line length should be agreed upon at the team-level. It's usually 80 or 120 characters. +ความยาวสูงสุดของบรรทัดควรตกลงกันในระดับทีมงาน ปกติแล้วมักเป็น 80 หรือ 120 ตัวอักษร -### Indents +### การเยื้องบรรทัด -There are two types of indents: +มี 2 วิธีในการเยื้องบรรทัด: -- **Horizontal indents: 2 or 4 spaces.** +- **การเยื้องในแนวนอน: เว้นวรรค 2 หรือ 4 ช่อง** - A horizontal indentation is made using either 2 or 4 spaces or the horizontal tab symbol (key `key:Tab`). Which one to choose is an old holy war. Spaces are more common nowadays. + การเยื้องในแนวนอนทำได้โดยใช้การเว้นวรรค 2 หรือ 4 ช่อง หรือใช้สัญลักษณ์แท็บ (ปุ่ม `key:Tab`) ที่จะเลือกใช้แบบไหนเป็นประเด็นถกเถียงกันมานาน ปัจจุบันนิยมใช้การเว้นวรรคมากกว่า - One advantage of spaces over tabs is that spaces allow more flexible configurations of indents than the tab symbol. + ข้อดีของการเว้นวรรคเหนือแท็บคือ สามารถกำหนดระยะการเยื้องได้ยืดหยุ่นกว่าการใช้สัญลักษณ์แท็บ - For instance, we can align the parameters with the opening bracket, like this: + ตัวอย่างเช่น เราสามารถจัดตำแหน่งพารามิเตอร์ให้ตรงกับวงเล็บเปิดได้ แบบนี้: ```js no-beautify show(parameters, - aligned, // 5 spaces padding at the left + aligned, // เว้นวรรค 5 ช่องจากทางซ้าย one, after, another @@ -129,9 +129,9 @@ There are two types of indents: } ``` -- **Vertical indents: empty lines for splitting code into logical blocks.** +- **การเว้นบรรทัดในแนวตั้ง: เว้นบรรทัดว่างเพื่อแบ่งโค้ดเป็นกลุ่มย่อยตามลำดับขั้นตอน** - Even a single function can often be divided into logical blocks. In the example below, the initialization of variables, the main loop and returning the result are split vertically: + แม้แต่ฟังก์ชันเดียวก็มักแบ่งเป็นกลุ่มย่อยตามลำดับขั้นตอนได้ ในตัวอย่างด้านล่างนี้ มีการแบ่งแยกส่วนการกำหนดค่าตัวแปรเริ่มต้น, ลูปหลัก และการส่งค่ากลับ ออกจากกันในแนวตั้ง: ```js function pow(x, n) { @@ -145,51 +145,51 @@ There are two types of indents: } ``` - Insert an extra newline where it helps to make the code more readable. There should not be more than nine lines of code without a vertical indentation. + เพิ่มบรรทัดว่างในจุดที่ช่วยให้อ่านโค้ดเข้าใจง่ายขึ้น ไม่ควรมีโค้ดยาวเกิน 9 บรรทัดโดยไม่มีการเว้นบรรทัดในแนวตั้ง -### Semicolons +### เครื่องหมายอัฒภาค (semicolon) -A semicolon should be present after each statement, even if it could possibly be skipped. +ควรมีอัฒภาคปิดท้ายแต่ละประโยคเสมอ แม้ในบางกรณีจะละเว้นได้ก็ตาม -There are languages where a semicolon is truly optional and it is rarely used. In JavaScript, though, there are cases where a line break is not interpreted as a semicolon, leaving the code vulnerable to errors. See more about that in the chapter . +บางภาษามีอัฒภาคเป็นตัวเลือกล้วนๆ และแทบไม่เห็นใช้เลย แต่ในภาษา JavaScript มีบางกรณีที่ตัวขึ้นบรรทัดใหม่ไม่ได้ถูกตีความเป็นอัฒภาค ทำให้โค้ดมีความเสี่ยงเกิดข้อผิดพลาดได้ อ่านรายละเอียดเพิ่มเติมในบท -If you're an experienced JavaScript programmer, you may choose a no-semicolon code style like [StandardJS](https://standardjs.com/). Otherwise, it's best to use semicolons to avoid possible pitfalls. The majority of developers put semicolons. +หากคุณเป็นโปรแกรมเมอร์ JavaScript ที่มีประสบการณ์สูง คุณอาจเลือกใช้สไตล์การเขียนโค้ดแบบไม่ใส่อัฒภาค เช่น [StandardJS](https://standardjs.com/) ได้ มิฉะนั้นแล้ว แนะนำให้ใส่อัฒภาคเสมอจะดีกว่า เพื่อหลีกเลี่ยงปัญหาที่อาจเกิดขึ้น นักพัฒนาส่วนใหญ่ใส่อัฒภาคในโค้ดเป็นปกติอยู่แล้ว -### Nesting Levels +### ระดับความลึกของการซ้อนโค้ด -Try to avoid nesting code too many levels deep. +พยายามหลีกเลี่ยงการซ้อนโค้ดลึกเกินไปหลายชั้น -For example, in the loop, it's sometimes a good idea to use the [`continue`](info:while-for#continue) directive to avoid extra nesting. +ยกตัวอย่างเช่น ในลูป บางครั้งการใช้คำสั่ง [`continue`](info:while-for#continue) เพื่อข้ามการซ้อนโค้ดเพิ่มเติมเป็นวิธีที่ดี -For example, instead of adding a nested `if` conditional like this: +เช่น แทนที่จะเพิ่มเงื่อนไข `if` ซ้อนกันแบบนี้: ```js for (let i = 0; i < 10; i++) { if (cond) { - ... // <- one more nesting level + ... // <- ซ้อนลึกลงไปอีกชั้น } } ``` -We can write: +เราสามารถเขียนเป็น: ```js for (let i = 0; i < 10; i++) { if (!cond) *!*continue*/!*; - ... // <- no extra nesting level + ... // <- ไม่ต้องซ้อนลึกลงไปอีกชั้น } ``` -A similar thing can be done with `if/else` and `return`. +สามารถทำแบบเดียวกันได้กับ `if/else` และ `return` -For example, two constructs below are identical. +ตัวอย่างเช่น โครงสร้างสองแบบด้านล่างนี้ให้ผลลัพธ์เหมือนกัน -Option 1: +แบบที่ 1: ```js function pow(x, n) { if (n < 0) { - alert("Negative 'n' not supported"); + alert("ไม่รองรับ 'n' ติดลบ"); } else { let result = 1; @@ -202,12 +202,12 @@ function pow(x, n) { } ``` -Option 2: +แบบที่ 2: ```js function pow(x, n) { if (n < 0) { - alert("Negative 'n' not supported"); + alert("ไม่รองรับ 'n' ติดลบ"); return; } @@ -221,102 +221,104 @@ function pow(x, n) { } ``` -The second one is more readable because the "special case" of `n < 0` is handled early on. Once the check is done we can move on to the "main" code flow without the need for additional nesting. +แบบที่สองอ่านเข้าใจง่ายกว่า เพราะจัดการ "กรณีพิเศษ" ที่ `n < 0` ตั้งแต่เนิ่นๆ เมื่อตรวจสอบผ่านแล้ว เราก็สามารถไปต่อที่โค้ดส่วนหลักได้เลย โดยไม่ต้องซ้อนโค้ดลึกลงไปอีก -## Function Placement +## การจัดวางตำแหน่งฟังก์ชัน -If you are writing several "helper" functions and the code that uses them, there are three ways to organize the functions. +หากคุณกำลังเขียนฟังก์ชัน "ผู้ช่วย" หลายๆ ฟังก์ชัน และโค้ดที่เรียกใช้ฟังก์ชันเหล่านั้น มีวิธีจัดวางฟังก์ชัน 3 แบบดังนี้ -1. Declare the functions *above* the code that uses them: +1. ประกาศฟังก์ชัน *ก่อน* โค้ดที่เรียกใช้: - ```js - // *!*function declarations*/!* - function createElement() { - ... - } + ```js + // *!*ประกาศฟังก์ชัน*/!* + function createElement() { + ... + } - function setHandler(elem) { - ... - } + function setHandler(elem) { + ... + } - function walkAround() { - ... - } + function walkAround() { + ... + } - // *!*the code which uses them*/!* - let elem = createElement(); - setHandler(elem); - walkAround(); - ``` -2. Code first, then functions + // *!*โค้ดที่เรียกใช้ฟังก์ชัน*/!* + let elem = createElement(); + setHandler(elem); + walkAround(); + ``` - ```js - // *!*the code which uses the functions*/!* - let elem = createElement(); - setHandler(elem); - walkAround(); - - // --- *!*helper functions*/!* --- - function createElement() { - ... - } +2. เขียนโค้ดที่เรียกใช้ฟังก์ชันก่อน จากนั้นตามด้วยฟังก์ชัน - function setHandler(elem) { - ... - } + ```js + // *!*โค้ดที่เรียกใช้ฟังก์ชัน*/!* + let elem = createElement(); + setHandler(elem); + walkAround(); - function walkAround() { - ... - } - ``` -3. Mixed: a function is declared where it's first used. + // --- *!*ฟังก์ชันผู้ช่วย*/!* --- + function createElement() { + ... + } + + function setHandler(elem) { + ... + } + + function walkAround() { + ... + } + ``` + +3. ผสมกันระหว่างสองแบบข้างต้น: ประกาศฟังก์ชันในตำแหน่งที่มีการเรียกใช้ครั้งแรก -Most of time, the second variant is preferred. +โดยส่วนใหญ่แล้ว นิยมใช้แบบที่ 2 มากกว่า -That's because when reading code, we first want to know *what it does*. If the code goes first, then it becomes clear from the start. Then, maybe we won't need to read the functions at all, especially if their names are descriptive of what they actually do. +เพราะเวลาอ่านโค้ด เราต้องการทราบก่อนว่า *โค้ดทำอะไร* ถ้าเขียนโค้ดไว้ข้างบนสุด ความตั้งใจของโค้ดจะชัดเจนตั้งแต่แรก และในบางครั้งเราอาจไม่จำเป็นต้องอ่านฟังก์ชันเลยก็ได้ โดยเฉพาะอย่างยิ่งเมื่อชื่อฟังก์ชันบ่งบอกหน้าที่ของมันได้ดีอยู่แล้ว -## Style Guides +## คู่มือสไตล์การเขียนโค้ด -A style guide contains general rules about "how to write" code, e.g. which quotes to use, how many spaces to indent, the maximal line length, etc. A lot of minor things. +คู่มือสไตล์ประกอบด้วยกฎทั่วไปเกี่ยวกับ "วิธีเขียน" โค้ด เช่น ควรใช้เครื่องหมายคำพูดแบบไหน เว้นย่อหน้ากี่ช่อง ความยาวสูงสุดของบรรทัดคือเท่าไร เป็นต้น ซึ่งเป็นรายละเอียดเล็กๆ น้อยๆ จำนวนมาก -When all members of a team use the same style guide, the code looks uniform, regardless of which team member wrote it. +เมื่อสมาชิกทุกคนในทีมใช้คู่มือสไตล์ชุดเดียวกัน โค้ดจะมีรูปแบบที่เป็นเอกภาพ ไม่ว่าจะเขียนโดยสมาชิกคนไหนก็ตาม -Of course, a team can always write their own style guide, but usually there's no need to. There are many existing guides to choose from. +แน่นอนว่า ทีมสามารถเขียนคู่มือสไตล์เป็นของตัวเองได้เสมอ แต่โดยทั่วไปแล้วมักไม่จำเป็น เพราะมีคู่มือสำเร็จรูปให้เลือกใช้อยู่แล้วมากมาย -Some popular choices: +ตัวเลือกยอดนิยมบางส่วน ได้แก่: - [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html) - [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) - [Idiomatic.JS](https://github.com/rwaldron/idiomatic.js) - [StandardJS](https://standardjs.com/) -- (plus many more) +- (และอีกมากมาย) -If you're a novice developer, start with the cheat sheet at the beginning of this chapter. Then you can browse other style guides to pick up more ideas and decide which one you like best. +สำหรับนักพัฒนามือใหม่ แนะนำให้เริ่มต้นจากตารางสรุปที่หัวข้อแรกของบทนี้ จากนั้นค่อยๆ ศึกษาคู่มือสไตล์อื่นๆ เพื่อเก็บเกี่ยวไอเดียเพิ่มเติม แล้วตัดสินใจเลือกสไตล์ที่ถูกใจที่สุด -## Automated Linters +## เครื่องมือตรวจสอบโค้ดอัตโนมัติ (Automated Linters) -Linters are tools that can automatically check the style of your code and make improving suggestions. +Linter คือเครื่องมือที่ช่วยตรวจสอบสไตล์โค้ดให้โดยอัตโนมัติ และเสนอแนะจุดที่ควรปรับปรุงแก้ไข -The great thing about them is that style-checking can also find some bugs, like typos in variable or function names. Because of this feature, using a linter is recommended even if you don't want to stick to one particular "code style". +ข้อดีคือ การตรวจสอบสไตล์ยังสามารถช่วยค้นพบบั๊กบางอย่างได้ด้วย เช่น การสะกดชื่อตัวแปรหรือฟังก์ชันผิด ด้วยเหตุนี้ จึงแนะนำให้ใช้ linter แม้คุณจะไม่อยากยึดติดกับ "สไตล์โค้ด" แบบใดแบบหนึ่งโดยเฉพาะก็ตาม -Here are some well-known linting tools: +ต่อไปนี้คือเครื่องมือ linting ที่มีชื่อเสียง: -- [JSLint](https://www.jslint.com/) -- one of the first linters. -- [JSHint](https://jshint.com/) -- more settings than JSLint. -- [ESLint](https://eslint.org/) -- probably the newest one. +- [JSLint](https://www.jslint.com/) -- หนึ่งใน linter รุ่นแรกๆ +- [JSHint](https://jshint.com/) -- มีตัวเลือกการตั้งค่ามากกว่า JSLint +- [ESLint](https://eslint.org/) -- น่าจะเป็นตัวล่าสุด -All of them can do the job. The author uses [ESLint](https://eslint.org/). +ทั้งหมดนี้ใช้งานได้เหมือนกัน ผู้เขียนเองใช้ [ESLint](https://eslint.org/) -Most linters are integrated with many popular editors: just enable the plugin in the editor and configure the style. +Linter ส่วนใหญ่ผสานรวมอยู่ในเครื่องมือแก้ไขโค้ดหลายตัวที่นิยมใช้กัน: เพียงเปิดใช้ปลั๊กอินในตัวแก้ไขโค้ด แล้วกำหนดค่าสไตล์ที่ต้องการ -For instance, for ESLint you should do the following: +ยกตัวอย่างสำหรับ ESLint ให้ทำตามขั้นตอนต่อไปนี้: -1. Install [Node.js](https://nodejs.org/). -2. Install ESLint with the command `npm install -g eslint` (npm is a JavaScript package installer). -3. Create a config file named `.eslintrc` in the root of your JavaScript project (in the folder that contains all your files). -4. Install/enable the plugin for your editor that integrates with ESLint. The majority of editors have one. +1. ติดตั้ง [Node.js](https://nodejs.org/) +2. ติดตั้ง ESLint ด้วยคำสั่ง `npm install -g eslint` (npm คือตัวจัดการแพ็คเกจของ JavaScript) +3. สร้างไฟล์กำหนดค่าชื่อ `.eslintrc` ไว้ที่ root ของโปรเจ็กต์ JavaScript (ในโฟลเดอร์ที่เก็บไฟล์ทั้งหมด) +4. ติดตั้ง/เปิดใช้ปลั๊กอินสำหรับเครื่องมือแก้ไขโค้ดที่เชื่อมต่อกับ ESLint โดยทั่วไปเครื่องมือแก้ไขโค้ดส่วนใหญ่จะมีปลั๊กอินนี้ -Here's an example of an `.eslintrc` file: +ตัวอย่างไฟล์ `.eslintrc` เป็นดังนี้: ```js { @@ -333,16 +335,16 @@ Here's an example of an `.eslintrc` file: } ``` -Here the directive `"extends"` denotes that the configuration is based on the "eslint:recommended" set of settings. After that, we specify our own. +ในที่นี้ คำสั่ง `"extends"` หมายถึงใช้การกำหนดค่าพื้นฐานจากชุด "eslint:recommended" จากนั้นเราก็ปรับแต่งเพิ่มเติมเอง -It is also possible to download style rule sets from the web and extend them instead. See for more details about installation. +นอกจากนี้ยังดาวน์โหลดชุดกฎสไตล์จากเว็บมาต่อยอดได้ด้วย ดูข้อมูลเพิ่มเติมเกี่ยวกับการติดตั้งได้ที่ -Also certain IDEs have built-in linting, which is convenient but not as customizable as ESLint. +IDE บางตัวก็มี linter ติดตั้งมาในตัวแล้ว ซึ่งสะดวกแต่ปรับแต่งได้ไม่เท่า ESLint -## Summary +## สรุป -All syntax rules described in this chapter (and in the style guides referenced) aim to increase the readability of your code. All of them are debatable. +กฎไวยากรณ์ทั้งหมดที่กล่าวถึงในบทนี้ (และในคู่มือสไตล์ที่อ้างถึง) ล้วนมีเป้าหมายเพื่อเพิ่มความสามารถในการอ่านทำความเข้าใจโค้ดของคุณ และทุกกฎก็สามารถถกเถียงได้ -When we think about writing "better" code, the questions we should ask ourselves are: "What makes the code more readable and easier to understand?" and "What can help us avoid errors?" These are the main things to keep in mind when choosing and debating code styles. +เมื่อเราคิดถึงการเขียนโค้ดให้ "ดีขึ้น" คำถามที่ควรถามตัวเองคือ "อะไรที่ช่วยให้โค้ดอ่านง่ายและทำความเข้าใจได้มากขึ้น" และ "อะไรที่ช่วยให้เราหลีกเลี่ยงข้อผิดพลาด" นี่คือสิ่งสำคัญที่ต้องคำนึงถึงเวลาเลือกหรือโต้แย้งสไตล์โค้ด -Reading popular style guides will allow you to keep up to date with the latest ideas about code style trends and best practices. +การอ่านคู่มือสไตล์ยอดนิยมจะช่วยให้คุณอัพเดตแนวคิดล่าสุดเกี่ยวกับเทรนด์และแนวปฏิบัติที่ดีที่สุดในการจัดสไตล์โค้ดได้ \ No newline at end of file diff --git a/1-js/03-code-quality/03-comments/article.md b/1-js/03-code-quality/03-comments/article.md index af3a06c80..6b92f2032 100644 --- a/1-js/03-code-quality/03-comments/article.md +++ b/1-js/03-code-quality/03-comments/article.md @@ -1,38 +1,38 @@ -# Comments +# คอมเมนต์ -As we know from the chapter , comments can be single-line: starting with `//` and multiline: `/* ... */`. +ดังที่เราได้เรียนรู้จากบท แล้วว่า คอมเมนต์สามารถเป็นบรรทัดเดียว: เริ่มต้นด้วย `//` หรือหลายบรรทัด: `/* ... */` -We normally use them to describe how and why the code works. +โดยปกติเราใช้คอมเมนต์เพื่ออธิบายว่าโค้ดทำงานอย่างไรและทำไมถึงทำงานแบบนั้น -At first sight, commenting might be obvious, but novices in programming often use them wrongly. +ในทีแรกการเขียนคอมเมนต์อาจดูเป็นเรื่องง่าย แต่มือใหม่ในการเขียนโปรแกรมมักใช้คอมเมนต์ในทางที่ผิด -## Bad comments +## คอมเมนต์ที่ไม่ดี -Novices tend to use comments to explain "what is going on in the code". Like this: +มือใหม่มักใช้คอมเมนต์เพื่ออธิบาย "สิ่งที่กำลังเกิดขึ้นในโค้ด" แบบนี้: ```js -// This code will do this thing (...) and that thing (...) -// ...and who knows what else... +// โค้ดนี้จะทำสิ่งนี้ (...) และสิ่งนั้น (...) +// ...และใครจะรู้ว่ามันยังทำอะไรอีก... very; complex; code; ``` -But in good code, the amount of such "explanatory" comments should be minimal. Seriously, the code should be easy to understand without them. +แต่ในโค้ดที่ดี ปริมาณของคอมเมนต์ "อธิบาย" แบบนี้ควรมีให้น้อยที่สุด จริงๆ แล้ว โค้ดควรอ่านเข้าใจได้ง่ายโดยไม่ต้องพึ่งคอมเมนต์ -There's a great rule about that: "if the code is so unclear that it requires a comment, then maybe it should be rewritten instead". +มีกฎสำคัญเกี่ยวกับเรื่องนี้: "ถ้าโค้ดไม่ชัดเจนจนต้องใช้คอมเมนต์ บางทีอาจควรเขียนโค้ดใหม่แทน" -### Recipe: factor out functions +### เคล็ดลับ: แยกโค้ดออกมาเป็นฟังก์ชัน -Sometimes it's beneficial to replace a code piece with a function, like here: +บางครั้งการแทนที่ส่วนหนึ่งของโค้ดด้วยฟังก์ชันก็มีประโยชน์ เหมือนในตัวอย่างนี้: ```js function showPrimes(n) { nextPrime: for (let i = 2; i < n; i++) { - + *!* - // check if i is a prime number + // ตรวจสอบว่า i เป็นจำนวนเฉพาะหรือไม่ for (let j = 2; j < i; j++) { if (i % j == 0) continue nextPrime; } @@ -43,8 +43,7 @@ function showPrimes(n) { } ``` -The better variant, with a factored out function `isPrime`: - +โค้ดที่ดีกว่า โดยการแยกเป็นฟังก์ชัน `isPrime` คือ: ```js function showPrimes(n) { @@ -52,7 +51,7 @@ function showPrimes(n) { for (let i = 2; i < n; i++) { *!*if (!isPrime(i)) continue;*/!* - alert(i); + alert(i); } } @@ -65,21 +64,21 @@ function isPrime(n) { } ``` -Now we can understand the code easily. The function itself becomes the comment. Such code is called *self-descriptive*. +ตอนนี้เราสามารถเข้าใจโค้ดได้ง่ายขึ้น ฟังก์ชันเองก็กลายเป็นคอมเมนต์ โค้ดแบบนี้เรียกว่า *อธิบายตัวเอง (self-descriptive)* -### Recipe: create functions +### เคล็ดลับ: สร้างฟังก์ชัน -And if we have a long "code sheet" like this: +หากเรามี "แผ่นโค้ด" ยาวๆ แบบนี้: ```js -// here we add whiskey +// ตรงนี้เติมวิสกี้ for(let i = 0; i < 10; i++) { let drop = getWhiskey(); smell(drop); add(drop, glass); } -// here we add juice +// ตรงนี้เติมน้ำผลไม้ for(let t = 0; t < 3; t++) { let tomato = getTomato(); examine(tomato); @@ -87,10 +86,10 @@ for(let t = 0; t < 3; t++) { add(juice, glass); } -// ... +// ... ``` -Then it might be a better variant to refactor it into functions like: +การ refactor ให้เป็นฟังก์ชันแบบนี้อาจดีกว่า: ```js addWhiskey(glass); @@ -108,73 +107,77 @@ function addJuice(container) { let tomato = getTomato(); //... } -} +} ``` -Once again, functions themselves tell what's going on. There's nothing to comment. And also the code structure is better when split. It's clear what every function does, what it takes and what it returns. +อีกครั้ง ตัวฟังก์ชันเองบอกเลยว่ากำลังเกิดอะไรขึ้น ไม่ต้องใช้คอมเมนต์อธิบาย และโครงสร้างโค้ดก็ดีขึ้นเมื่อแยกส่วนออกมา มองชัดเจนว่าแต่ละฟังก์ชันทำอะไร รับอะไรเข้ามา และส่งอะไรออกไป -In reality, we can't totally avoid "explanatory" comments. There are complex algorithms. And there are smart "tweaks" for purposes of optimization. But generally we should try to keep the code simple and self-descriptive. +ในความเป็นจริง เราไม่สามารถหลีกเลี่ยงคอมเมนต์ "อธิบาย" ได้ทั้งหมด มีอัลกอริธึมที่ซับซ้อน และมี "กลเม็ด" ที่ชาญฉลาดที่ใช้เพื่อปรับปรุงประสิทธิภาพโค้ด แต่โดยทั่วไปแล้ว เราควรพยายามรักษาให้โค้ดเรียบง่ายและอธิบายตัวเองได้มากที่สุด -## Good comments +## คอมเมนต์ที่ดี -So, explanatory comments are usually bad. Which comments are good? +ดังนั้น คอมเมนต์ที่เป็นคำอธิบายมักจะไม่ดี แล้วคอมเมนต์แบบไหนถึงจะดีล่ะ? -Describe the architecture -: Provide a high-level overview of components, how they interact, what's the control flow in various situations... In short -- the bird's eye view of the code. There's a special language [UML](http://wikipedia.org/wiki/Unified_Modeling_Language) to build high-level architecture diagrams explaining the code. Definitely worth studying. +อธิบายสถาปัตยกรรม +: ให้ภาพรวมในระดับสูงของส่วนประกอบต่างๆ ว่ามีปฏิสัมพันธ์กันอย่างไร อะไรคือลำดับการควบคุมในสถานการณ์ต่างๆ สั้นๆ ก็คือมุมสูงของโค้ด มีภาษาพิเศษอย่าง [UML](http://wikipedia.org/wiki/Unified_Modeling_Language) ที่ใช้สร้างแผนภาพสถาปัตยกรรมในระดับสูงเพื่ออธิบายโค้ด ซึ่งแน่นอนว่าคุ้มค่าแก่การศึกษา -Document function parameters and usage -: There's a special syntax [JSDoc](http://en.wikipedia.org/wiki/JSDoc) to document a function: usage, parameters, returned value. +บันทึกพารามิเตอร์และการใช้งานฟังก์ชัน +: มีไวยากรณ์พิเศษอย่าง [JSDoc](http://en.wikipedia.org/wiki/JSDoc) สำหรับบันทึกข้อมูลฟังก์ชัน: วิธีใช้งาน พารามิเตอร์ ค่าที่ส่งคืน -For instance: +ตัวอย่างเช่น: ```js /** - * Returns x raised to the n-th power. + * ส่งคืน x ยกกำลัง n * - * @param {number} x The number to raise. - * @param {number} n The power, must be a natural number. - * @return {number} x raised to the n-th power. + * @param {number} x เลขที่ต้องการยกกำลัง + * @param {number} n เลขชี้กำลัง ต้องเป็นจำนวนนับ + * @return {number} x ยกกำลัง n */ function pow(x, n) { ... } ``` -Such comments allow us to understand the purpose of the function and use it the right way without looking in its code. +คอมเมนต์แบบนี้ช่วยให้เราเข้าใจวัตถุประสงค์ของฟังก์ชันและใช้งานอย่างถูกต้องโดยไม่ต้องดูที่โค้ด -By the way, many editors like [WebStorm](https://www.jetbrains.com/webstorm/) can understand them as well and use them to provide autocomplete and some automatic code-checking. +ในทางกลับกัน เครื่องมือแก้ไขโค้ดหลายตัวเช่น [WebStorm](https://www.jetbrains.com/webstorm/) ก็สามารถอ่านคอมเมนต์เหล่านี้และใช้เพื่อช่วยเติมโค้ดอัตโนมัติและตรวจสอบโค้ดบางอย่างโดยอัตโนมัติได้ +<<<<<<< HEAD +และยังมีเครื่องมืออย่าง [JSDoc 3](https://github.com/jsdoc/jsdoc) ที่สามารถสร้างเอกสาร HTML จากคอมเมนต์ คุณสามารถอ่านข้อมูลเพิ่มเติมเกี่ยวกับ JSDoc ได้ที่ +======= Also, there are tools like [JSDoc 3](https://github.com/jsdoc/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at . +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -Why is the task solved this way? -: What's written is important. But what's *not* written may be even more important to understand what's going on. Why is the task solved exactly this way? The code gives no answer. +ทำไมปัญหาถึงได้รับการแก้ไขด้วยวิธีนี้? +: สิ่งที่เขียนไว้นั้นสำคัญ แต่สิ่งที่ *ไม่ได้* เขียนอาจจะสำคัญยิ่งกว่าในการทำความเข้าใจว่ากำลังเกิดอะไรขึ้น ทำไมปัญหาถึงถูกแก้ไขด้วยวิธีนี้พอดี? โค้ดไม่ได้ให้คำตอบ - If there are many ways to solve the task, why this one? Especially when it's not the most obvious one. + ถ้ามีหลายวิธีในการแก้ปัญหา ทำไมถึงเลือกวิธีนี้? โดยเฉพาะอย่างยิ่งเมื่อมันไม่ใช่ทางเลือกที่ชัดเจนที่สุด - Without such comments the following situation is possible: - 1. You (or your colleague) open the code written some time ago, and see that it's "suboptimal". - 2. You think: "How stupid I was then, and how much smarter I'm now", and rewrite using the "more obvious and correct" variant. - 3. ...The urge to rewrite was good. But in the process you see that the "more obvious" solution is actually lacking. You even dimly remember why, because you already tried it long ago. You revert to the correct variant, but the time was wasted. + หากไม่มีคอมเมนต์ดังกล่าว สถานการณ์ต่อไปนี้อาจเกิดขึ้นได้: + 1. คุณ (หรือเพื่อนร่วมงาน) เปิดโค้ดที่เขียนไว้เมื่อสักพักก่อน แล้วเห็นว่ามัน "ไม่เหมาะสมที่สุด" + 2. คุณคิดว่า "ตอนนั้นโง่จัง ส่วนตอนนี้ฉันฉลาดขึ้นมากแล้ว" และเขียนใหม่ด้วยทางเลือกที่ "ตรงไปตรงมาและถูกต้องกว่า" + 3. ...แรงผลักดันที่จะเขียนใหม่เป็นสิ่งที่ดี แต่ระหว่างนั้นคุณเห็นว่าวิธีที่ "ตรงไปตรงมา" นั้นจริงๆ แล้วไม่ครบถ้วน คุณพอจำได้เลือนราง ว่าทำไมถึงเป็นแบบนั้น เพราะเคยลองทำไปแล้วเมื่อนานมาแล้ว คุณเปลี่ยนกลับมาใช้วิธีที่ถูกต้อง แต่ก็เสียเวลาไปแล้ว - Comments that explain the solution are very important. They help to continue development the right way. + คอมเมนต์ที่อธิบายวิธีแก้ปัญหานั้นสำคัญมาก ช่วยให้พัฒนาต่อไปในทิศทางที่ถูกต้อง -Any subtle features of the code? Where they are used? -: If the code has anything subtle and counter-intuitive, it's definitely worth commenting. +โค้ดมีจุดอ่อนหรือเทคนิคพิเศษซ่อนอยู่ไหม? ใช้แบบนี้ที่ไหนบ้าง? +: ถ้าโค้ดมีอะไรที่ละเอียดอ่อนและขัดกับสัญชาตญาณ ก็ควรคอมเมนต์ไว้อย่างยิ่ง -## Summary +## สรุป -An important sign of a good developer is comments: their presence and even their absence. +สัญญาณสำคัญของนักพัฒนาที่ดีคือคอมเมนต์: ทั้งการมีและการไม่มีของมัน -Good comments allow us to maintain the code well, come back to it after a delay and use it more effectively. +คอมเมนต์ที่ดีช่วยให้เรารักษาโค้ดไว้ได้ดี กลับมาดูอีกครั้งหลังจากผ่านไประยะหนึ่ง และใช้งานได้อย่างมีประสิทธิภาพยิ่งขึ้น -**Comment this:** +**ควรเขียนคอมเมนต์เรื่อง:** -- Overall architecture, high-level view. -- Function usage. -- Important solutions, especially when not immediately obvious. +- สถาปัตยกรรมโดยรวม, มุมมองภาพกว้าง +- วิธีใช้ฟังก์ชัน +- วิธีแก้ปัญหาที่สำคัญ โดยเฉพาะเมื่อไม่เห็นได้ชัดในทันที -**Avoid comments:** +**หลีกเลี่ยงคอมเมนต์ที่:** -- That tell "how code works" and "what it does". -- Put them in only if it's impossible to make the code so simple and self-descriptive that it doesn't require them. +- บอก "โค้ดทำงานอย่างไร" และ "ทำอะไร" +- ใส่คอมเมนต์เฉพาะเมื่อทำให้โค้ดเรียบง่ายและอธิบายตัวเองจนไม่จำเป็นต้องใช้คอมเมนต์แล้วไม่ได้ -Comments are also used for auto-documenting tools like JSDoc3: they read them and generate HTML-docs (or docs in another format). +คอมเมนต์ยังถูกใช้โดยเครื่องมือสร้างเอกสารอัตโนมัติอย่าง JSDoc3: อ่านคอมเมนต์และสร้างเอกสาร HTML (หรือเอกสารในรูปแบบอื่น) จากมัน \ No newline at end of file diff --git a/1-js/03-code-quality/04-ninja-code/article.md b/1-js/03-code-quality/04-ninja-code/article.md index 96fdf4143..ef0b8dfd6 100644 --- a/1-js/03-code-quality/04-ninja-code/article.md +++ b/1-js/03-code-quality/04-ninja-code/article.md @@ -1,185 +1,182 @@ -# Ninja code +# โค้ดนินจา - -```quote author="Confucius (Analects)" -Learning without thought is labor lost; thought without learning is perilous. +```quote author="ขงจื๊อ (วจนะ)" +เรียนไร้คิดเหนื่อยเปล่าดุจดั่งฝัน คิดไร้เรียนอันตรายใช่น้อยเลย ``` -Programmer ninjas of the past used these tricks to sharpen the mind of code maintainers. - -Code review gurus look for them in test tasks. +โปรแกรมเมอร์นินจาในอดีตใช้กลเม็ดเหล่านี้เพื่อลับสมองของผู้ดูแลโค้ด -Novice developers sometimes use them even better than programmer ninjas. +ผู้เชี่ยวชาญการรีวิวโค้ดมองหากลเม็ดเหล่านี้ในการทดสอบงาน -Read them carefully and find out who you are -- a ninja, a novice, or maybe a code reviewer? +บางครั้งนักพัฒนามือใหม่ใช้กลเม็ดเหล่านี้ได้ดีกว่าโปรแกรมเมอร์นินจาเสียอีก +อ่านอย่างละเอียดแล้วลองดูว่าคุณเป็นใคร -- นินจา, มือใหม่, หรืออาจเป็นผู้รีวิวโค้ด? -```warn header="Irony detected" -Many try to follow ninja paths. Few succeed. +```warn header="พบการเสียดสี" +มากมายมุ่งวิถีนินจา น้อยนักล่วงพ้นถึงจุดหมาย ``` +## ความกระชับคือหัวใจของปัญญา -## Brevity is the soul of wit +เขียนโค้ดให้สั้นที่สุดเท่าที่จะทำได้ เพื่อแสดงความฉลาดของคุณ -Make the code as short as possible. Show how smart you are. +ให้คุณลักษณะภาษาที่ซับซ้อนเป็นตัวนำทาง -Let subtle language features guide you. - -For instance, take a look at this ternary operator `'?'`: +ยกตัวอย่างเช่น ลองดูตัวดำเนินการแบบ 3 ทาง (ternary) `'?'` นี้: ```js -// taken from a well-known javascript library +// มาจากไลบรารี JavaScript ที่มีชื่อเสียง i = i ? i < 0 ? Math.max(0, len + i) : i : 0; ``` -Cool, right? If you write like that, a developer who comes across this line and tries to understand what is the value of `i` is going to have a merry time. Then come to you, seeking for an answer. +เจ๋งใช่ไหม? ถ้าคุณเขียนแบบนี้ นักพัฒนาที่เจอบรรทัดนี้และพยายามทำความเข้าใจว่า `i` มีค่าเท่าไหร่ คงจะได้เพลิดเพลิน จากนั้นก็มาหาคุณเพื่อขอคำตอบ -Tell them that shorter is always better. Initiate them into the paths of ninja. +บอกพวกเขาว่าสั้นกว่าดีกว่าเสมอ แนะนำพวกเขาสู่วิถีแห่งนินจา -## One-letter variables +## ตัวแปรตัวอักษรเดียว -```quote author="Laozi (Tao Te Ching)" -The Dao hides in wordlessness. Only the Dao is well begun and well -completed. +```quote author="เล่าจื๊อ (เต๋าเต๋อจิง)" +เต๋าซ่อนในความเงียบไร้คำ เริ่มต้นและจบลงอย่างสมบูรณ์ ``` -Another way to code shorter is to use single-letter variable names everywhere. Like `a`, `b` or `c`. +อีกวิธีหนึ่งที่จะเขียนโค้ดให้สั้นลงคือการใช้ชื่อตัวแปรเพียงตัวอักษรเดียวทุกที่ เช่น `a`, `b` หรือ `c` -A short variable disappears in the code like a real ninja in the forest. No one will be able to find it using "search" of the editor. And even if someone does, they won't be able to "decipher" what the name `a` or `b` means. +ตัวแปรที่สั้นจะหายไปในโค้ดเหมือนนินจาในป่า ไม่มีใครสามารถหาเจอได้ด้วยฟีเจอร์ "ค้นหา" ของเครื่องมือแก้ไขโค้ด และถึงแม้ใครจะเจอ พวกเขาก็คงไม่สามารถ "ถอดรหัส" ได้ว่า `a` หรือ `b` หมายถึงอะไร -...But there's an exception. A real ninja will never use `i` as the counter in a `"for"` loop. Anywhere, but not here. Look around, there are many more exotic letters. For instance, `x` or `y`. +...แต่มีข้อยกเว้น นินจาตัวจริงจะไม่มีวันใช้ `i` เป็นตัวนับในลูป `"for"` ยกเว้นตรงนี้ที่ไหนก็ได้ มองหารอบๆ ดู มีตัวอักษรแปลกๆ อีกมากมาย เช่น `x` หรือ `y` -An exotic variable as a loop counter is especially cool if the loop body takes 1-2 pages (make it longer if you can). Then if someone looks deep inside the loop, they won't be able to quickly figure out that the variable named `x` is the loop counter. +ใช้ตัวแปรแปลกตาเป็นตัวนับลูปนี่เจ๋งสุดๆ โดยเฉพาะถ้าภายในลูปยาว 1-2 หน้า (ยิ่งยาวยิ่งดี) เพราะถ้ามีใครมาดูโค้ดข้างในลูป พวกเขาจะไม่สามารถเดาได้ในทันทีว่าตัวแปรชื่อ `x` คือตัวนับลูป -## Use abbreviations -If the team rules forbid the use of one-letter and vague names -- shorten them, make abbreviations. +## ใช้คำย่อ -Like this: +หากกฎของทีมห้ามใช้ชื่อที่เป็นตัวอักษรเดียวหรือคลุมเครือ -- ก็ให้ย่อมัน สร้างคำย่อขึ้นมา -- `list` -> `lst`. -- `userAgent` -> `ua`. -- `browser` -> `brsr`. -- ...etc +แบบนี้: -Only the one with truly good intuition will be able to understand such names. Try to shorten everything. Only a worthy person should be able to uphold the development of your code. +- `list` -> `lst` +- `userAgent` -> `ua` +- `browser` -> `brsr` +- ...ฯลฯ -## Soar high. Be abstract. +มีเพียงคนที่มีสัญชาตญาณดีเยี่ยมเท่านั้นที่จะเข้าใจชื่อแบบนี้ได้ พยายามย่อทุกอย่าง มีแต่คนที่เหมาะสมเท่านั้นที่จะสามารถดูแลพัฒนาโค้ดของคุณต่อได้ -```quote author="Laozi (Tao Te Ching)" -The great square is cornerless
-The great vessel is last complete,
-The great note is rarified sound,
-The great image has no form. -``` +## โบยบินสูงส่ง ดั่งนามธรรม -While choosing a name try to use the most abstract word. Like `obj`, `data`, `value`, `item`, `elem` and so on. +```quote author="เล่าจื๊อ (เต๋าเต๋อจิง)" +สี่เหลี่ยมใหญ่ไร้มุมแหลมคม +ภาชนะยิ่งใหญ่เสร็จสิ้นท้ายสุด +เสียงอันไพเราะคือความเบาบาง +ภาพอันยิ่งใหญ่ไร้รูปทรง +``` -- **The ideal name for a variable is `data`.** Use it everywhere you can. Indeed, every variable holds *data*, right? +ในการตั้งชื่อ พยายามเลือกใช้คำที่เป็นนามธรรมที่สุด เช่น `obj`, `data`, `value`, `item`, `elem` และอื่นๆ - ...But what to do if `data` is already taken? Try `value`, it's also universal. After all, a variable eventually gets a *value*. +- **`data` คือชื่อตัวแปรในอุดมคติ** ใช้มันทุกที่ที่ทำได้ เพราะตัวแปรทุกตัวมี *ข้อมูล* จริงไหม? -- **Name a variable by its type: `str`, `num`...** + ...แต่ถ้า `data` ถูกใช้ไปแล้วล่ะ? ลองใช้ `value` แทน เพราะมันก็เป็นคำสากลเหมือนกัน ท้ายที่สุดตัวแปรก็มี *ค่า* อยู่ดี - Give them a try. A young initiate may wonder -- are such names really useful for a ninja? Indeed, they are! +- **ตั้งชื่อตัวแปรตามชนิดข้อมูล: `str`, `num`...** - Sure, the variable name still means something. It says what's inside the variable: a string, a number or something else. But when an outsider tries to understand the code, they'll be surprised to see that there's actually no information at all! And will ultimately fail to alter your well-thought code. + ลองใช้ดู มือใหม่อาจสงสัยว่าชื่อแบบนั้นมีประโยชน์จริงหรือสำหรับนินจา? แน่นอน มีประโยชน์จริงๆ! - The value type is easy to find out by debugging. But what's the meaning of the variable? Which string/number does it store? + ชื่อตัวแปรก็ยังพอบอกอะไรได้บ้าง มันบอกว่าข้างในเก็บอะไร: สตริง, ตัวเลข หรืออย่างอื่น แต่ถ้าคนนอกพยายามอ่านโค้ด เขาจะแปลกใจเมื่อพบว่ามันไม่ได้ให้ข้อมูลอะไรเลย! และก็จะแก้โค้ดที่คุณคิดมาอย่างดีไม่ได้สักที - There's just no way to figure out without a good meditation! + หาชนิดข้อมูลได้ง่ายโดยการดีบัก แต่ความหมายของตัวแปรล่ะ? มันเก็บสตริง/ตัวเลขอะไรกันแน่? -- **...But what if there are no more such names?** Just add a number: `data1, item2, elem5`... + ไม่มีทางรู้ได้เลย นอกจากจะทำสมาธิให้ดี! -## Attention test +- **...แล้วถ้าชื่อแบบนั้นไม่เหลือแล้วล่ะ?** ก็แค่เติมตัวเลขต่อท้าย: `data1, item2, elem5`... -Only a truly attentive programmer should be able to understand your code. But how to check that? +## ทดสอบความใส่ใจ -**One of the ways -- use similar variable names, like `date` and `data`.** +มีแค่โปรแกรมเมอร์ที่ใส่ใจจริงๆ เท่านั้นถึงจะเข้าใจโค้ดของคุณได้ แต่จะตรวจสอบได้ยังไง? -Mix them where you can. +**หนึ่งในวิธีคือใช้ชื่อตัวแปรที่คล้ายกัน เช่น `date` กับ `data`** -A quick read of such code becomes impossible. And when there's a typo... Ummm... We're stuck for long, time to drink tea. +ใช้สลับกันไปมาตามที่ทำได้ +การอ่านโค้ดผ่านๆ จะเป็นไปไม่ได้เลย แล้วถ้ามีการพิมพ์ผิดอีก... อืม... คงได้ติดอยู่กับมันนาน ถึงเวลาไปดื่มชากันแล้ว -## Smart synonyms +## คำพ้องความหมาย -```quote author="Laozi (Tao Te Ching)" -The Tao that can be told is not the eternal Tao. The name that can be named is not the eternal name. +```quote author="เล่าจื๊อ (เต๋าเต๋อจิง)" +เต๋าที่กล่าวได้มิใช่เต๋านิรันดร์ นามที่เอ่ยได้มิใช่นามอมตะ ``` -Using *similar* names for *same* things makes life more interesting and shows your creativity to the public. +การใช้ชื่อ *คล้ายๆ กัน* กับสิ่งที่ *เหมือนๆ กัน* ทำให้ชีวิตสนุกขึ้น และแสดงความคิดสร้างสรรค์ของคุณให้คนอื่นเห็น -For instance, consider function prefixes. If a function shows a message on the screen -- start it with `display…`, like `displayMessage`. And then if another function shows on the screen something else, like a user name, start it with `show…` (like `showName`). +เช่น คำนำหน้าฟังก์ชัน ถ้าฟังก์ชันแสดงข้อความบนจอ ให้ขึ้นต้นด้วย `display...` อย่าง `displayMessage` แล้วถ้ามีอีกฟังก์ชันที่แสดงอย่างอื่นบนจอ เช่นชื่อผู้ใช้ ก็ขึ้นต้นด้วย `show...` แทน (อย่าง `showName`) -Insinuate that there's a subtle difference between such functions, while there is none. +ทำให้รู้สึกเหมือนมันมีความต่างแบบประณีต ทั้งที่จริงๆ ไม่ได้ต่างกันเลย -Make a pact with fellow ninjas of the team: if John starts "showing" functions with `display...` in his code, then Peter could use `render..`, and Ann -- `paint...`. Note how much more interesting and diverse the code became. +ทำสัญญากับเพื่อนนินจาในทีมว่า ถ้าจอห์นเริ่มฟังก์ชัน "แสดง" ด้วย `display...` ในโค้ดของเขา ปีเตอร์จะใช้ `render...` ส่วนแอนใช้ `paint...` สังเกตว่าโค้ดจะน่าสนใจและหลากหลายมากขึ้นแค่ไหน -...And now the hat trick! +...แล้วนี่คือไม้เด็ด! -For two functions with important differences -- use the same prefix! +สำหรับสองฟังก์ชันที่แตกต่างกันชัดเจน ให้ใช้คำนำหน้าเดียวกัน! -For instance, the function `printPage(page)` will use a printer. And the function `printText(text)` will put the text on-screen. Let an unfamiliar reader think well over similarly named function `printMessage`: "Where does it put the message? To a printer or on the screen?". To make it really shine, `printMessage(message)` should output it in the new window! +อย่างเช่น ฟังก์ชัน `printPage(page)` จะส่งไปเครื่องพิมพ์ ส่วน `printText(text)` จะแสดงข้อความบนจอ ให้คนอ่านที่ไม่คุ้นคิดหนักกับฟังก์ชัน `printMessage` ที่มีชื่อคล้ายๆ กันว่า "มันส่งข้อความไปไหนนะ เครื่องพิมพ์หรือบนจอ?" จะเจ๋งขึ้นไปอีกถ้า `printMessage(message)` แสดงผลในหน้าต่างใหม่! -## Reuse names +## ใช้ชื่อซ้ำ -```quote author="Laozi (Tao Te Ching)" -Once the whole is divided, the parts
-need names.
-There are already enough names.
-One must know when to stop. +```quote author="เล่าจื๊อ (เต๋าเต๋อจิง)" +เมื่อแบ่งสรรพสิ่งออกเป็นส่วนย่อย +แต่ละส่วนล้วนต้องการชื่อเรียกขาน +นามทั้งหลายมีอยู่มากมายแล้ว +รู้จักพอคือคุณูปการอันล้ำค่า ``` -Add a new variable only when absolutely necessary. +อย่าเพิ่มตัวแปรใหม่ถ้าไม่จำเป็นจริงๆ -Instead, reuse existing names. Just write new values into them. +แทนที่จะทำแบบนั้น ให้นำชื่อที่มีอยู่แล้วมาใช้ใหม่ แค่เขียนค่าใหม่ลงไปแทนที่ค่าเดิม -In a function try to use only variables passed as parameters. +ภายในฟังก์ชัน พยายามใช้เฉพาะตัวแปรที่ส่งเข้ามาเป็นพารามิเตอร์เท่านั้น -That would make it really hard to identify what's exactly in the variable *now*. And also where it comes from. The purpose is to develop the intuition and memory of a person reading the code. A person with weak intuition would have to analyze the code line-by-line and track the changes through every code branch. +วิธีนี้จะทำให้แทบเป็นไปไม่ได้เลยที่จะระบุได้ว่าอะไรอยู่ในตัวแปร *ตอนนี้* และมาจากไหน จุดประสงค์คือเพื่อฝึกสัญชาตญาณและความจำของคนที่อ่านโค้ด คนที่สัญชาตญาณไม่ดีจะต้องวิเคราะห์โค้ดทีละบรรทัดและติดตามการเปลี่ยนแปลงข้ามทุกการแตกแขนงของโค้ด -**An advanced variant of the approach is to covertly (!) replace the value with something alike in the middle of a loop or a function.** +**รูปแบบขั้นสูงของวิธีนี้คือการแอบ (!) เปลี่ยนค่าเป็นอย่างอื่นที่คล้ายๆ กันระหว่างวนลูปหรือทำงานในฟังก์ชัน** -For instance: +ตัวอย่างเช่น: ```js function ninjaFunction(elem) { - // 20 lines of code working with elem + // 20 บรรทัดโค้ดที่ทำงานกับ elem elem = clone(elem); - // 20 more lines, now working with the clone of the elem! + // อีก 20 บรรทัด ตอนนี้ทำงานกับ clone ของ elem! } ``` -A fellow programmer who wants to work with `elem` in the second half of the function will be surprised... Only during the debugging, after examining the code they will find out that they're working with a clone! - -Seen in code regularly. Deadly effective even against an experienced ninja. +โปรแกรมเมอร์ที่ต้องการทำงานกับ `elem` ในครึ่งหลังของฟังก์ชันจะงงแน่ๆ... จนกว่าจะลองดีบักและไล่ดูโค้ด ถึงจะรู้ว่ากำลังทำงานกับตัวโคลนอยู่! -## Underscores for fun +เจอแบบนี้ในโค้ดบ่อยมาก ได้ผลดีถึงตายแม้กับนินจาจอมเก๋า -Put underscores `_` and `__` before variable names. Like `_name` or `__value`. It would be great if only you knew their meaning. Or, better, add them just for fun, without particular meaning at all. Or different meanings in different places. +## ใช้ underscore ให้สนุก -You kill two rabbits with one shot. First, the code becomes longer and less readable, and the second, a fellow developer may spend a long time trying to figure out what the underscores mean. +ใส่ underscore `_` และ `__` ข้างหน้าชื่อตัวแปร เช่น `_name` หรือ `__value` ถ้ามีแค่คุณที่รู้ความหมายคงจะดีมาก หรือดีกว่านั้น ใส่มันลงไปเพื่อความสนุกเฉยๆ โดยไม่มีความหมายพิเศษอะไรเลย หรือมีความหมายต่างกันในแต่ละที่ก็ได้ -A smart ninja puts underscores at one spot of code and evades them at other places. That makes the code even more fragile and increases the probability of future errors. +คุณจะฆ่าสองนกในหินก้อนเดียว หนึ่ง โค้ดจะยาวขึ้นและอ่านยากขึ้น และสอง เพื่อนนักพัฒนาอาจเสียเวลาไปเยอะกับการพยายามหาว่า underscore หมายถึงอะไร -## Show your love +นินจาเก๋าจะวาง underscore ไว้ที่หนึ่งในโค้ด แล้วไม่ใส่อีกที่นึง นั่นจะยิ่งทำให้โค้ดเปราะบางและเพิ่มโอกาสเกิดข้อผิดพลาดในอนาคต -Let everyone see how magnificent your entities are! Names like `superElement`, `megaFrame` and `niceItem` will definitely enlighten a reader. +## แสดงความรัก -Indeed, from one hand, something is written: `super..`, `mega..`, `nice..` But from the other hand -- that brings no details. A reader may decide to look for a hidden meaning and meditate for an hour or two of their paid working time. +ให้ทุกคนได้เห็นความวิเศษของ entity ต่างๆ ของคุณ! ชื่อเช่น `superElement`, `megaFrame` และ `niceItem` จะทำให้ผู้อ่านรู้สึกเปล่งประกายแน่ๆ +ก็จริงอยู่ มีอะไรบางอย่างถูกเขียนไว้: `super..`, `mega..`, `nice..` แต่ในอีกแง่หนึ่ง มันก็ไม่ได้ให้รายละเอียดอะไรเลย ผู้อ่านอาจตัดสินใจค้นหาความหมายที่ซ่อนอยู่และนั่งสมาธิสักชั่วโมงสองชั่วโมงในเวลางานที่ได้ค่าจ้าง -## Overlap outer variables +## ใช้ชื่อซ้ำกับตัวแปรด้านนอก -```quote author="Guan Yin Zi" -When in the light, can't see anything in the darkness.
-When in the darkness, can see everything in the light. +```quote author="กวนอินจื้อ" +ท่ามกลางแสงมืดมิดไร้ภาพ +ในความมืดกลับประจักษ์แสงสว่าง +สองขั้วต่างพึ่งพาอาศัย +เผยนัยลึกล้ำแห่งสรรพสิ่ง ``` -Use same names for variables inside and outside a function. As simple. No efforts to invent new names. +ใช้ชื่อเดียวกันสำหรับตัวแปรทั้งในและนอกฟังก์ชัน แค่นี้แหละ ไม่ต้องพยายามคิดชื่อใหม่ ```js let *!*user*/!* = authenticateUser(); @@ -187,54 +184,52 @@ let *!*user*/!* = authenticateUser(); function render() { let *!*user*/!* = anotherValue(); ... - ...many lines... + ...หลายบรรทัด... ... - ... // <-- a programmer wants to work with user here and... + ... // <-- โปรแกรมเมอร์อยากทำงานกับ user ตรงนี้และ... ... } ``` -A programmer who jumps inside the `render` will probably fail to notice that there's a local `user` shadowing the outer one. - -Then they'll try to work with `user` assuming that it's the external variable, the result of `authenticateUser()`... The trap is sprung! Hello, debugger... - +โปรแกรมเมอร์ที่ข้ามเข้ามาใน `render` อาจไม่ทันสังเกตว่ามี `user` ในฟังก์ชันกำลังบดบัง `user` ด้านนอกอยู่ -## Side-effects everywhere! +แล้วเขาจะพยายามทำงานกับ `user` โดยคิดว่ามันคือตัวแปรจากภายนอก ซึ่งเป็นผลลัพธ์จาก `authenticateUser()` ... กับดักถูกปล่อยแล้ว! สวัสดี debugger ... -There are functions that look like they don't change anything. Like `isReady()`, `checkPermission()`, `findTags()`... They are assumed to carry out calculations, find and return the data, without changing anything outside of them. In other words, without "side-effects". +## ผลข้างเคียงได้ทุกที่! -**A really beautiful trick is to add a "useful" action to them, besides the main task.** +มีฟังก์ชันบางอย่างที่ดูเหมือนไม่ได้เปลี่ยนแปลงอะไรเลย เช่น `isReady()`, `checkPermission()`, `findTags()` ... มักคาดหวังว่าฟังก์ชันพวกนี้จะคำนวณ ค้นหา และคืนข้อมูล โดยไม่แปรเปลี่ยนสิ่งใดภายนอก หรือก็คือ ไม่มี "ผลข้างเคียง" -An expression of dazed surprise on the face of your colleague when they see a function named `is..`, `check..` or `find...` changing something -- will definitely broaden your boundaries of reason. +**กลเม็ดสุดเจ๋งคือแอบใส่การกระทำที่ "มีประโยชน์" เข้าไป นอกเหนือจากงานหลัก** -**Another way to surprise is to return a non-standard result.** +สีหน้าประหลาดใจงงงวยของเพื่อนร่วมงาน เมื่อเห็นฟังก์ชันชื่อ `is..`, `check..` หรือ `find...` ที่ดันไปเปลี่ยนแปลงอะไรบางอย่าง จะช่วยขยายขอบเขตความคิดของคุณแน่นอน -Show your original thinking! Let the call of `checkPermission` return not `true/false`, but a complex object with the results of the check. +**อีกวิธีที่จะสร้างความประหลาดใจคือส่งคืนผลลัพธ์แบบไม่ปกติ** -Those developers who try to write `if (checkPermission(..))`, will wonder why it doesn't work. Tell them: "Read the docs!". And give this article. +แสดงความคิดริเริ่มของคุณ! ให้ `checkPermission` คืนค่าไม่ใช่แค่ `true/false` แต่เป็นอ็อบเจ็กต์ที่ซับซ้อนพร้อมผลการตรวจสอบ +นักพัฒนาที่พยายามเขียน `if (checkPermission(..))` จะสงสัยว่าทำไมมันถึงใช้ไม่ได้ บอกพวกเขาไปเลยว่า "อ่านเอกสารกำกับสิ!" แล้วก็ส่งลิงก์บทความนี้ให้ -## Powerful functions! +## ฟังก์ชันอันทรงพลัง! -```quote author="Laozi (Tao Te Ching)" -The great Tao flows everywhere,
-both to the left and to the right. +```quote author="เล่าจื๊อ (เต๋าเต๋อจิง)" +มหาเต๋าไหลทั่วทุกหนแห่ง +ทั้งซ้ายขวาล้วนซึมซาบ ``` -Don't limit the function by what's written in its name. Be broader. +อย่าจำกัดฟังก์ชันด้วยสิ่งที่เขียนไว้ในชื่อของมัน จงมองให้กว้างไกลกว่านั้น -For instance, a function `validateEmail(email)` could (besides checking the email for correctness) show an error message and ask to re-enter the email. +ยกตัวอย่างเช่น ฟังก์ชัน `validateEmail(email)` อาจแสดงข้อผิดพลาดและขอให้กรอกอีเมลใหม่ด้วย (นอกเหนือจากการตรวจสอบความถูกต้องของอีเมล) -Additional actions should not be obvious from the function name. A true ninja coder will make them not obvious from the code as well. +การกระทำเพิ่มเติมไม่ควรชัดเจนจากชื่อฟังก์ชัน นินจาเขียนโค้ดตัวจริงจะทำให้มองไม่ออกจากในโค้ดเช่นกัน -**Joining several actions into one protects your code from reuse.** +**การรวมหลายการกระทำเข้าด้วยกันจะปกป้องโค้ดของคุณจากการนำไปใช้ซ้ำ** -Imagine, another developer wants only to check the email, and not output any message. Your function `validateEmail(email)` that does both will not suit them. So they won't break your meditation by asking anything about it. +สมมติว่ามีนักพัฒนาอีกคนต้องการแค่เช็คอีเมลเฉยๆ โดยไม่ต้องแสดงข้อความใดๆ ฟังก์ชัน `validateEmail(email)` ของคุณที่ทำงานทั้งสองอย่างจะไม่เหมาะกับเขา แบบนี้เขาจะไม่มารบกวนสมาธิของคุณด้วยการมาถามคำถามใดๆ เกี่ยวกับมัน -## Summary +## สรุป -All "pieces of advice" above are from the real code... Sometimes, written by experienced developers. Maybe even more experienced than you are ;) +"เคล็ดลับ" ข้างต้นทั้งหมดมาจากโค้ดของจริง... บางครั้งเขียนโดยนักพัฒนาผู้มากประสบการณ์ บางทีอาจจะมากกว่าคุณด้วยซ้ำ ;) -- Follow some of them, and your code will become full of surprises. -- Follow many of them, and your code will become truly yours, no one would want to change it. -- Follow all, and your code will become a valuable lesson for young developers looking for enlightenment. +- ทำตามบางข้อ และโค้ดของคุณจะเต็มไปด้วยเรื่องน่าประหลาดใจ +- ทำตามหลายๆ ข้อ และโค้ดจะกลายเป็นของคุณโดยแท้จริง ไม่มีใครอยากเปลี่ยนแปลงมัน +- ทำตามทุกข้อ และโค้ดของคุณจะกลายเป็นบทเรียนอันล้ำค่าสำหรับนักพัฒนาหน้าใหม่ผู้แสวงหาการรู้แจ้ง diff --git a/1-js/03-code-quality/05-testing-mocha/article.md b/1-js/03-code-quality/05-testing-mocha/article.md index 4c2b1aa5e..2e6c01305 100644 --- a/1-js/03-code-quality/05-testing-mocha/article.md +++ b/1-js/03-code-quality/05-testing-mocha/article.md @@ -1,72 +1,86 @@ -# Automated testing with Mocha +# การทดสอบอัตโนมัติด้วย Mocha -Automated testing will be used in further tasks, and it's also widely used in real projects. +ในงานต่อๆ ไปจะมีการใช้การทดสอบอัตโนมัติ ซึ่งเป็นสิ่งที่ใช้กันอย่างแพร่หลายในโปรเจ็กต์จริงด้วย -## Why do we need tests? +## ทำไมต้องมีการทดสอบ? -When we write a function, we can usually imagine what it should do: which parameters give which results. +เวลาเขียนฟังก์ชัน เรามักจะจินตนาการได้ว่ามันควรจะทำงานอย่างไร พารามิเตอร์แบบไหนให้ผลลัพธ์แบบไหน -During development, we can check the function by running it and comparing the outcome with the expected one. For instance, we can do it in the console. +ระหว่างพัฒนา เราตรวจสอบฟังก์ชันได้โดยการรันและเปรียบเทียบผลลัพธ์กับสิ่งที่คาดหวังไว้ เช่น อาจทำในคอนโซล -If something is wrong -- then we fix the code, run again, check the result -- and so on till it works. +ถ้ามีอะไรผิดพลาด ก็แก้โค้ด รันใหม่ เช็คผลลัพธ์ วนไปแบบนี้จนกว่าจะใช้ได้ -But such manual "re-runs" are imperfect. +แต่การ "รันซ้ำ" ด้วยมือแบบนั้นยังไม่สมบูรณ์แบบ -**When testing a code by manual re-runs, it's easy to miss something.** +**เมื่อทดสอบโค้ดโดยการรันซ้ำเอง มักจะมีบางอย่างหลุดไปได้ง่าย** -For instance, we're creating a function `f`. Wrote some code, testing: `f(1)` works, but `f(2)` doesn't work. We fix the code and now `f(2)` works. Looks complete? But we forgot to re-test `f(1)`. That may lead to an error. +ยกตัวอย่างเช่น สมมติเรากำลังเขียนฟังก์ชัน `f` เขียนโค้ดนิดหน่อย ลองทดสอบดู `f(1)` ใช้ได้ แต่ `f(2)` ไม่ทำงาน เราแก้โค้ดแล้วตอนนี้ `f(2)` ก็ใช้ได้แล้ว ดูเหมือนจะครบแล้วใช่ไหม แต่เราลืมย้อนกลับไปเทสต์ `f(1)` ใหม่ ซึ่งอาจจะมีข้อผิดพลาดโผล่ขึ้นมาก็ได้ -That's very typical. When we develop something, we keep a lot of possible use cases in mind. But it's hard to expect a programmer to check all of them manually after every change. So it becomes easy to fix one thing and break another one. +นี่เป็นเรื่องปกติมาก ตอนที่เรากำลังพัฒนาอะไรบางอย่าง มักจะมีหลายกรณีการใช้งานที่เราต้องคำนึงถึง แต่การที่จะให้โปรแกรมเมอร์มานั่งเช็คทุกกรณีด้วยตัวเองทุกครั้งที่มีการเปลี่ยนแปลง เป็นเรื่องยาก เลยกลายเป็นว่าแก้ไขอย่างหนึ่ง แล้วไปทำให้อีกอย่างพังได้ง่าย -**Automated testing means that tests are written separately, in addition to the code. They run our functions in various ways and compare results with the expected.** +**การทดสอบอัตโนมัติหมายถึงการเขียนเทสต์แยกออกมาต่างหาก เป็นส่วนเสริมของโค้ด เทสต์เหล่านั้นจะรันฟังก์ชันของเราในหลากหลายวิธี และเปรียบเทียบผลลัพธ์กับสิ่งที่คาดหวัง** ## Behavior Driven Development (BDD) -Let's start with a technique named [Behavior Driven Development](http://en.wikipedia.org/wiki/Behavior-driven_development) or, in short, BDD. +เรามาเริ่มต้นด้วยเทคนิคที่เรียกว่า [Behavior Driven Development](http://en.wikipedia.org/wiki/Behavior-driven_development) หรือเรียกสั้นๆ ว่า BDD กัน -**BDD is three things in one: tests AND documentation AND examples.** +**BDD คือ 3 สิ่งในหนึ่งเดียว ทั้งเทสต์ เอกสาร และตัวอย่างการใช้งาน** -To understand BDD, we'll examine a practical case of development. +เพื่อทำความเข้าใจ BDD เราจะมาดูตัวอย่างกรณีศึกษาในการพัฒนาซอฟต์แวร์กัน -## Development of "pow": the spec +## การพัฒนา "pow": ข้อกำหนด -Let's say we want to make a function `pow(x, n)` that raises `x` to an integer power `n`. We assume that `n≥0`. +สมมติว่าเราอยากเขียนฟังก์ชัน `pow(x, n)` ที่คืนค่า `x` ยกกำลังด้วยเลขชี้กำลังจำนวนเต็ม `n` โดยเราสมมติว่า `n≥0` -That task is just an example: there's the `**` operator in JavaScript that can do that, but here we concentrate on the development flow that can be applied to more complex tasks as well. +จริงๆ แล้วนี่เป็นแค่ตัวอย่าง เพราะในจาวาสคริปต์มีตัวดำเนินการ `**` ที่ทำแบบนี้ได้อยู่แล้ว แต่ตรงนี้เราจะมุ่งเน้นไปที่วิธีการพัฒนาที่สามารถนำไปประยุกต์ใช้กับงานที่ซับซ้อนกว่านี้ได้ด้วย -Before creating the code of `pow`, we can imagine what the function should do and describe it. +ก่อนจะเขียนโค้ดของ `pow` เราสามารถจินตนาการถึงสิ่งที่ฟังก์ชันควรจะทำและบรรยายมันไว้ก่อนได้ -Such description is called a *specification* or, in short, a spec, and contains descriptions of use cases together with tests for them, like this: +คำบรรยายแบบนี้เรียกว่า *ข้อกำหนด (specification)* หรือเรียกสั้นๆ ว่า spec ซึ่งจะประกอบด้วยรายละเอียดกรณีการใช้งานต่างๆ ร่วมกับเทสต์สำหรับกรณีเหล่านั้น ดังนี้ ```js describe("pow", function() { - it("raises to n-th power", function() { + it("ยกกำลัง n", function() { assert.equal(pow(2, 3), 8); }); }); ``` -A spec has three main building blocks that you can see above: +spec มีองค์ประกอบหลัก 3 ส่วนตามที่เห็นข้างบน +<<<<<<< HEAD +`describe("ชื่อหัวข้อ", function() { ... })` +: เรากำลังอธิบายฟังก์ชันอะไร? ในกรณีนี้คือฟังก์ชัน `pow` ใช้เพื่อจัดกลุ่มบล็อก `it` ที่เป็น "ผู้ทำงาน" +======= `describe("title", function() { ... })` : What functionality we're describing? In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -`it("use case description", function() { ... })` -: In the title of `it` we *in a human-readable way* describe the particular use case, and the second argument is a function that tests it. +`it("คำอธิบายกรณีการใช้งาน", function() { ... })` +: ในชื่อของ `it` จะบรรยาย *ในรูปแบบที่คนอ่านแล้วเข้าใจ* ถึงกรณีการใช้งานเฉพาะ และอาร์กิวเมนต์ตัวที่สองก็จะเป็นฟังก์ชันที่ทดสอบกรณีดังกล่าว `assert.equal(value1, value2)` -: The code inside `it` block, if the implementation is correct, should execute without errors. +: โค้ดภายในบล็อก `it` ถ้าอิมพลีเมนต์ถูกต้อง ควรจะรันได้โดยไม่เกิดข้อผิดพลาด - Functions `assert.*` are used to check whether `pow` works as expected. Right here we're using one of them -- `assert.equal`, it compares arguments and yields an error if they are not equal. Here it checks that the result of `pow(2, 3)` equals `8`. There are other types of comparisons and checks, that we'll add later. + ฟังก์ชัน `assert.*` ถูกใช้เพื่อเช็คว่า `pow` ทำงานได้ตามที่คาดหวังหรือไม่ ตรงนี้เราใช้ตัวหนึ่งในนั้นคือ `assert.equal` มันจะเปรียบเทียบอาร์กิวเมนต์และโยนข้อผิดพลาดถ้าไม่เท่ากัน ซึ่งตรงนี้เช็คว่าผลลัพธ์ของ `pow(2, 3)` เท่ากับ `8` รึเปล่า นอกจากนี้ยังมีชนิดอื่นๆ ของการเปรียบเทียบและตรวจสอบด้วย ซึ่งเราจะมาเพิ่มภายหลัง -The specification can be executed, and it will run the test specified in `it` block. We'll see that later. +spec นี้สามารถรันได้ และมันจะไปรันเทสต์ที่อยู่ในบล็อก `it` เราจะมาดูเรื่องนี้กันในภายหลัง -## The development flow +## ขั้นตอนการพัฒนา -The flow of development usually looks like this: +ขั้นตอนการพัฒนามักจะเป็นแบบนี้: +<<<<<<< HEAD +1. เขียนข้อกำหนด (spec) เบื้องต้น พร้อมกับเทสต์สำหรับฟังก์ชันที่พื้นฐานที่สุด +2. สร้างการอิมพลีเมนต์เบื้องต้น +3. เพื่อตรวจสอบว่ามันใช้ได้ไหม เราจะรันเฟรมเวิร์กการทดสอบ [Mocha](https://mochajs.org/) (จะมีรายละเอียดเพิ่มเติมเร็วๆ นี้) ที่จะรันข้อกำหนด ถ้าฟังก์ชันยังไม่ครบถ้วน ข้อผิดพลาดก็จะถูกแสดง เราจะทยอยแก้ไขจนกว่าทุกอย่างจะทำงาน +4. ตอนนี้เรามีการอิมพลีเมนต์เบื้องต้นที่ใช้ได้จริงพร้อมกับเทสต์แล้ว +5. เราเพิ่มกรณีการใช้งานเข้าไปในข้อกำหนด ซึ่งอาจยังไม่ได้รองรับโดยการอิมพลีเมนต์ เทสต์เริ่มล้มเหลว +6. กลับไปทำข้อ 3 ปรับแก้การอิมพลีเมนต์จนกระทั่งเทสต์ไม่มีข้อผิดพลาด +7. ทำข้อ 3-6 ซ้ำไปเรื่อยๆ จนกระทั่งฟังก์ชันลิตี้เสร็จสมบูรณ์ +======= 1. An initial spec is written, with tests for the most basic functionality. 2. An initial implementation is created. 3. To check whether it works, we run the testing framework [Mocha](https://mochajs.org/) (more details soon) that runs the spec. While the functionality is not complete, errors are displayed. We make corrections until everything works. @@ -74,119 +88,131 @@ The flow of development usually looks like this: 5. We add more use cases to the spec, probably not yet supported by the implementations. Tests start to fail. 6. Go to 3, update the implementation till tests give no errors. 7. Repeat steps 3-6 till the functionality is ready. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -So, the development is *iterative*. We write the spec, implement it, make sure tests pass, then write more tests, make sure they work etc. At the end we have both a working implementation and tests for it. +ดังนั้น การพัฒนาจึงเป็นแบบ *วนซ้ำ (iterative)* เราเขียนข้อกำหนด อิมพลีเมนต์มัน ตรวจสอบให้แน่ใจว่าเทสต์ผ่าน จากนั้นเขียนเทสต์เพิ่ม ตรวจว่าเทสต์ทำงานไหม แล้วก็ทำแบบนี้ต่อไป ท้ายที่สุดเราจะได้ทั้งการอิมพลีเมนต์ที่ใช้งานได้จริง พร้อมกับเทสต์สำหรับมัน -Let's see this development flow in our practical case. +มาดูกระบวนการพัฒนานี้ในกรณีของเราเป็นรูปธรรมกันดีกว่า +<<<<<<< HEAD +ตอนนี้เราทำขั้นตอนแรกเสร็จแล้ว คือมีข้อกำหนดเบื้องต้นของ `pow` ซึ่งก่อนจะลงมือเขียนอิมพลีเมนต์ เรามาลองใช้ไลบรารี JavaScript บางตัวเพื่อรันเทสต์ดู แค่เพื่อจะได้เห็นว่าเทสต์เหล่านั้นทำงานอยู่ (ตอนนี้เทสต์ทั้งหมดน่าจะล้มเหลว) +======= The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use a few JavaScript libraries to run the tests, just to see that they are working (they will all fail). +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -## The spec in action +## ข้อกำหนดที่ใช้งานจริง -Here in the tutorial we'll be using the following JavaScript libraries for tests: +ในบทเรียนนี้ เราจะใช้ไลบรารี JavaScript ต่อไปนี้ในการทดสอบ: +<<<<<<< HEAD +- [Mocha](https://mochajs.org/) -- เป็นเฟรมเวิร์กหลัก ให้ฟังก์ชันทดสอบทั่วไปต่างๆ รวมทั้ง `describe` และ `it` ตลอดจนฟังก์ชันหลักที่ใช้รันการทดสอบ +- [Chai](https://www.chaijs.com/) -- ไลบรารีที่มี assertions มากมาย ช่วยให้ใช้ assertions หลากหลายแบบได้ สำหรับตอนนี้เราต้องการแค่ `assert.equal` +- [Sinon](https://sinonjs.org/) -- ไลบรารีที่ใช้เฝ้าดูฟังก์ชัน จำลองการทำงานของฟังก์ชันในตัว และอื่นๆ เราจะต้องใช้มันในภายหลัง +======= - [Mocha](https://mochajs.org/) -- the core framework: it provides common testing functions including `describe` and `it` and the main function that runs tests. - [Chai](https://www.chaijs.com/) -- the library with many assertions. It allows to use a lot of different assertions, for now we need only `assert.equal`. - [Sinon](https://sinonjs.org/) -- a library to spy over functions, emulate built-in functions and more, we'll need it much later. +>>>>>>> 5e893cffce8e2346d4e50926d5148c70af172533 -These libraries are suitable for both in-browser and server-side testing. Here we'll consider the browser variant. +ไลบรารีเหล่านี้สามารถใช้ทดสอบได้ทั้งฝั่งเบราว์เซอร์และเซิร์ฟเวอร์ แต่ที่นี่เราจะพูดถึงกรณีบนเบราว์เซอร์ -The full HTML page with these frameworks and `pow` spec: +หน้า HTML เต็มรูปแบบที่มีเฟรมเวิร์กเหล่านี้พร้อมกับข้อกำหนดของ `pow`: ```html src="index.html" ``` -The page can be divided into five parts: +หน้านี้ประกอบด้วย 5 ส่วน: -1. The `` -- add third-party libraries and styles for tests. -2. The `