การรับค่าและการแสดงผล ในภาษา JavaScript
ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับการรับค่าและการแสดงผลในภาษา JavaScript; ภาษา JavaScript นั้นเป็นภาษาที่รันอยู่บน Host environment และไม่มีฟังก์ชันสำหรับการรับค่าเป็นของมันเอง ในบทนี้เราจะพูดถึงการรับค่าและแสดงผลบน Command line ที่รันบน Node.js เท่านั้น เราจะไม่พูดถึงการรับค่าและแสดงผลด้วยฟังก์ชันบนเบราวน์เซอร์อย่างเช่น prompt
และ alert
และนี่เป็นเนื้อหาในบทนี้
- การแสดงผลออกทางหน้าจอ
- การแสดงผลด้วยการแทนที่ใน String
- การแสดงผลด้วย process.stdout.write
- การรับค่าผ่านทางคีย์บอร์ด (Node.js)
- การรับค่าจาก Command line อาร์กิวเมนต์
- Escape characters
การแสดงผลออกทางหน้าจอ
ฟังก์ชัน console.log
เป็นฟังก์ชันสำหรับแสดงข้อมูลทุกประเภทออกทางหน้าจอในภาษา JavaScript เมื่อเรารันของโค้ดภาษา JavaScript บน Node.js การแสดงผลจะผ่าน Command Line (Console) หรือ Terminal ในขณะที่บนเว็บเบราว์เซอร์การแสดงผลจะผ่านเว็บ Console แทน
นี่เป็นตัวอย่างการใช้งานฟังก์ชัน console.log
เพื่อแสดงข้อมูลในภาษา JavaScript
console.log("JavaScript");
console.log(12);
console.log(true);
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
JavaScript
12
true
ในตัวอย่าง เราได้ใช้ฟังก์ชัน console.log
เพื่อแสดง Literal ของข้อความ ตัวเลข และ Boolean ออกทางหน้าจอตามลำดับ
สังเกตว่าค่าที่ถูกแสดงออกมาในแต่ละคำสั่งนั้นจะอยู่คนละบรรทัดกัน นั่นเป็นเพราะว่าฟังก์ชัน console.log
จะแสดงการขึ้นบรรทัดใหม่ "\n"
หลังจากที่แสดงค่าของพารามิเตอร์ด้วยเสมอ
นอกจากนี้ เรายังสามารถส่งหลายพารามิเตอร์เข้าไปยังฟังก์ชันได้ ยกตัวอย่างเช่น
console.log("JavaScript", "TypeScript");
console.log(1, 2, 3, 4, 5);
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
JavaScript TypeScript
1 2 3 4 5
ในตัวอย่าง แสดงให้เห็นว่าเราสามารถส่งพารามิเตอร์มากกว่าหนึ่งเข้าไปยังฟังก์ชันได้ โดยแต่ละค่าที่แสดงออกมานั้นจะคั่นด้วยช่องว่าง
ฟังก์ชัน console.log
ไม่เพียงแค่สามารถแสดงข้อมูลพื้นฐานได้เท่านั้น แต่มันยังสามารถใช้แสดงอออบเจ็ค อาเรย์ ฟังก์ชัน หรือข้อมูลทุกประเภทในภาษา JavaScript
let user = {
name: "Metin",
age: 28
};
function hello() {
console.log("Hello World!");
}
console.log(user);
console.log([10, 20, 30, 40, 50]);
console.log(hello);
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
{ name: 'Metin', age: 28 }
[ 10, 20, 30, 40, 50 ]
[Function: hello]
ในตัวอย่าง แสดงให้เห็นว่าฟังก์ชัน console.log
นั้นจะแสดงค่าต่างๆ ออกมาในรูปแบบ Literal ของข้อมูล ยกเว้นฟังก์ชันที่แสดงในรูปแบบของ String ที่เป็นชื่อของมัน นี่จะทำให้เราสามารถใช้มันเพื่อ Debug ค่าจากออบเจ็คประเภทต่างๆ ได้เป็นอย่างดี
การแสดงผลด้วยการแทนที่ใน String
นอกจากแสดงผลข้อมูล ตัวแปร หรือออบเจ็คแบบปกติแล้ว ฟังก์ชัน console.log
ยังสนับสนุนการแสดงผลด้วยการแทนที่ใน String อีกด้วย โดยการกำหนดพารามิเตอร์แรกเป็น Format string สำหรับจัดรูปแบบการแสดงผล ซึ่ง Format string นั้นจะประกอบไปด้วยตัวกำหนดการแสดงผล (Specifier) ที่แสดงดังในตารางต่อไปนี้
ตัวกำหนดการแสดงผล | คำอธิบาย |
---|---|
%o หรือ %O | แสดงผลออบเจ็คในภาษา JavaScript |
%d | แสดงผลตัวเลข |
%i | แสดงผลตัวเลขจำนวนเต็ม |
%s | แสดงผลข้อความ |
%f | แสดงผลตัวเลขทศนิยม |
ในการใช้งานฟังก์ชัน console.log
สำหรับจัดรูปแบบการแสดงผลด้วยการแทนที่ใน String นั้น ถ้าหากพารามิเตอร์แรกเป็น String ที่มี Specifier ที่ปรากฏในตารางด้านบน ฟังก์ชันจะทำงานในรูปแบบของการแทนที่ใน String แทน
นี่เป็นตัวอย่างการแสดงผลด้วยการแทนที่ใน String ในภาษา JavaScript
let name = "Metin";
let height = 6.2;
console.log("%s is %f inches height", name, height);
console.log("%d + %d = %d", 3, 5, 3 + 5);
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
Metin is 6.2 inches height
3 + 5 = 8
ในตัวอย่าง การแสดงผลในบรรทัดแรก เนื่องจากพารามิเตอร์แรกนั้นประกอบไปด้วยตัวจัดรูปแบบการแสดงผล %s
และ %f
นั่นหมายความว่าการทำงานของฟังก์ชันจะเป็นแบบการแทนค่าใน String พารามิเตอร์ตัวต่อไปจะถูกนำไปแทนที่ในตัวกำหนดรูปแบบตามลำดับที่มันปรากฏใน Format string
console.log("%s is %f inches height", name, height);
ดังนั้นค่าของพารามิเตอร์ name
จะถูกนำไปแทนที่ %s
และถัดมาพารามิเตอร์ height
จะถูกนำไปแทนที่ %f
ตามลำดับ และแสดงออกมาทางหน้าจอ
console.log("%d + %d = %d", 3, 5, 3 + 5);
ในบรรทัดต่อมา ได้มีการกำหนดตัวกำหนดรูปแบบการแสดง %d
สามตัวใน Format string ดังนั้นฟังก์ชันต้องการพารามิเตอร์อีกสามตัวสำหรับการทำงาน เราได้ส่งค่าตัวเลขเข้าไปยังฟังก์ชันโดยตรง
ตัวอย่างต่อมาเป็นการใช้ตัวกำหนดการแสดงผล %o
เพื่อแสดงค่าของออบเจ็คพร้อมกับ String
let user = {
name: "Metin",
safary: 50000,
single: true
};
console.log("Inspect object (%o)", user);
console.log("Inspect object (", user, ")");
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
Inspect object ({ name: 'Metin', safary: 50000, single: true })
Inspect object ( { name: 'Metin', safary: 50000, single: true } )
ในตัวอย่าง เป็นการแสดงค่าของออบเจ็ค เนื่องจากเราต้องการแสดงค่าของออบเจ็คภายในวงเล็บ (
...)
ดังนั้นการแทนที่ String นั้นเป็นวิธีที่ดีที่เราสามารถทำได้
Inspect object ( { name: 'Metin', safary: 50000, single: true } )
และถึงแม้ว่าเราจะสามารถใช้การส่งค่าแบบหลายพารามิเตอร์ในการแสดงผลบรรทัดที่สอง แต่ฟังก์ชัน console.log
จะแสดงเว้นวรรคระหว่างแต่ละพารามิเตอร์ด้วยเสมอ ซึ่งแน่นอนว่านี่ไม่ใช่สิ่งที่เราต้องการ
ตัวอย่างต่อมาเป็นการใช้การแทนที่ String ในการแปลงข้อมูลก่อนการแสดงผล เราสามารถใช้ตัวกำหนดรูปแบบการแสดงผลใดๆ สำหรับข้อมูลประเภทใดๆ ก็ได้ โปรแกรมจะพยายามแปลงค่าจากพารามิเตอร์ให้เป็นประเภทข้อมูลที่ตรงกับตัวกำหนดรูปแบบการแสดงผลที่ระบุไว้ใน Format string นี่เป็นตัวอย่าง
console.log("%i", 3.14);
console.log("%s", { name: "Metin", age: 28 });
console.log("Date: %s", new Date());
console.log("Timestamp: %d", new Date());
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
3
{ name: 'Metin', age: 28 }
Date: 2020-07-29T13:37:20.942Z
Timestamp: 1596029840942
ในตัวอย่าง นี่เป็นการบังคับการแสดงผลโดยกำหนดตัวจัดรูปแบบการแสดงผลเป็นประเภทข้อมูลที่ไม่เหมือนกับพารามิเตอร์ของมัน
console.log("%i", 3.14);
console.log("%s", { name: "Metin", age: 28 });
เนื่องจากตัวกำหนดการแสดงผล %i
ใช้สำหรับแสดงตัวเลขจำนวนเต็ม ดังนั้น 3.14
จะถูกแปลงเป็นจำนวนเต็มก่อนการแสดงผล และบรรทัดต่อมาเป็นการแสดงออบเจ็คในรูปแบบของ String ด้วย %s
console.log("Date: %s", new Date());
console.log("Timestamp: %d", new Date());
ถัดมาเป็นการแสดงออบเจ็คของวันที่ในรูปแบบของ String ค่าของออบเจ็คถูกแปลงเป็น String จากการเรียกใช้งานเมธอด toString
บนออบเจ็ค และสำหรับบรรทัดต่อมา ออบเจ็คของวันที่จะถูกแปลงเป็นตัวเลข ทำให้ได้รับค่าของ Timestamp แทน
คุณอาจจะไม่เห็นความแตกต่างอย่างชัดเจนระหว่างการใช้ %s
และ %o
สำหรับแสดงออบเจ็ค นั่นเป็นเพราะว่าค่าในออบเจ็คนั้นเป็นประเภทข้อมูลพื้นฐาน ซึ่่งมันจะถูกแสดงตาม Literal ของข้อมูลนั้นๆ ยกตัวอย่างเช่น
let user = {
name: "Metin",
age: 28
};
console.log("%s", user); // { name: 'Metin', age: 28 }
console.log("%o", user); // { name: 'Metin', age: 28 }
จากตัวอย่างด้านบน ทั้งสองคำสั่งนั้นจะให้ผลลัพธ์ที่เหมือนกัน แต่นี่จะทำให้ชัดเจนเมื่อออบเจ็คนั้นประกอบไปด้วยข้อมูลประเภทอื่นๆ ยกตัวอย่างเช่น ฟังก์ชัน
let user = {
name: "Metin",
age: 28,
sayHi: function() {
console.log("Hi");
},
birthDate: {
month: 3,
year: 1988
}
};
console.log("%s", user);
console.log("%o", user);
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
{
name: 'Metin',
age: 28,
sayHi: [Function: sayHi],
birthDate: [Object]
}
{
name: 'Metin',
age: 28,
sayHi: [Function: sayHi] {
[length]: 0,
[name]: 'sayHi',
[arguments]: null,
[caller]: null,
[prototype]: sayHi { [constructor]: [Circular] }
},
birthDate: { month: 3, year: 1988 }
}
และอย่างที่คุณเห็น %s
จะแปลงออบเจ็คเป็น String โดยออบเจ็คย่อยภายในนั้นจะถูกแปลงในรูปแบบที่เรียบง่ายที่สุดเท่าที่จะเป็นไปได้ ในขณะที่ %o
จะแสดงโครงสร้างทั้งหมดของออบเจ็ค รวมทั้ง Property ย่อยภายในออบเจ็ค
ฟังก์ชัน console.log
นั้นเป็นฟังก์ชันมาตฐานสำหรับแสดงข้อมูลในภาษา JavaScript ที่สามารถใช้ได้ในทุก Host environment อย่างไรก็ตาม เนื้อหาหลังจากนี้จะเป็นการพูดถึงฟังก์ชันสำหรับรับค่าและแสดงผลที่เฉพาะบน Node.js เท่านั้น นั่นหมายความว่ามันอาจจะไม่ทำงานบน Host environment อื่นๆ เช่น เว็บเบราวน์เซอร์
การแสดงผลด้วยฟังก์ชัน process.stdout.write (Node.js)
ฟังก์ชัน console.log
ใช้สำหรับแสดงข้อมูลออกทางหน้าจอที่มีการขึ้นบรรทัดใหม่ อย่างไรก็ตาม เมื่อเราเขียน JavaScript บน Node.js เราสามารถใช้ฟังก์ชัน process.stdout.write
สำหรับการแสดงผลออกทางหน้าจอได้ ทั้งสองฟังก์ชันนี้ใช้สำหรับแสดงผลออกทางหน้าจอเหมือนกัน แต่สิ่งที่แตกต่างกันมีดังนี้
การทำงาน | console.log | process.stdout.write |
---|---|---|
การขึ้นบรรทัดใหม่ | มี | ไม่มี |
ประเภทพารามิเตอร์ | ออบเจ็คทุกประเภท | String เท่านั้น |
จำนวนพารามิเตอร์ | หลายตัว | หนึ่งตัวเท่านั้น |
จากในตารางนั้นเป็นข้อแตกต่างหลักๆ ที่จะมีผลต่อเราในการเลือกใช้งานฟังก์ชัน process.stdout.write
สำหรับการแสดงผลแทนฟังก์ชัน console.log
ต่อไปมาดูตัวอย่างการแสดงตัวเลขจาก 0 - 4
ออกทางหน้าจอโดยการใช้ฟังก์ชันทั้งสอง
for (let i = 0; i < 5; i++) {
console.log(i);
}
for (let i = 0; i < 5; i++) {
process.stdout.write(i.toString());
}
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
0
1
2
3
4
01234
ในตัวอย่าง เราใช้คำสั่ง for loop สำหรับวนสร้างตัวเลขและแสดงออกมาทางหน้าจอ และอย่างที่เรารู้ว่าฟังก์ชัน console.log
จะแสดงการขึ้นบรรทัดใหม่ด้วยเสมอ และเราส่งค่าตัวเลขเข้าไปในฟังก์ชันโดยตรง ในขณะที่ลูปที่สองนั้นเราใช้ฟังก์ชัน process.stdout.write
สำหรับการแสดงผล
process.stdout.write(i.toString());
ฟังก์ชันนี้ไม่แสดงการขึ้นบรรทัดใหม่ และอีกสิ่งหนึ่งที่สำคัญสำหรับการใช้งานฟังก์ชันนี้ก็คือพารามิเตอร์ที่ส่งเข้าไปต้องเป็น String เท่านั้น ดังนั้นเราจึงเรียกใช้เมธอด toString
เพื่อแปลงตัวเลขเป็น String ก่อน
ต่อมาเป็นตัวอย่างของโปรแกรมที่แสดงความคืบหน้าของการดาวน์โหลดจาก 1 - 100% และถ้าหากค่าของเปอร์เซนต์ยังไม่ถึง 100% เราได้ทำการลบค่าเดิมออกไปโดยการถอย Cursor การแสดงผลกลับไปตำแหน่งแรกของ Console นี่เป็นเหตุผลที่เราไม่ต้องการให้การแสดงผลขึ้นบรรทัดใหม่และใช้ฟังก์ชัน process.stdout.write
สำหรับแสดงเปอร์เซนต์ นี่เป็นโค้ดของโปรแกรม
let percent = 0;
let buffer = "";
console.log("Initialing system");
let timerId = setInterval(function () {
process.stdout.write("\b".repeat(buffer.length));
if (percent >= 100) {
clearInterval(timerId);
console.log("100% Completed");
console.log("The system has been started");
return;
}
buffer = "Loading " + percent + "%";
process.stdout.write(buffer);
percent++;
}, 40);
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
Initialing system
100% Completed
The system has been started
คุณจะต้องรันโปรแกรมเพื่อดูการทำงานของมัน
ในตัวอย่างนี้ เป็นการจำลองโปรแกรมที่มีการโหลดข้อมูลก่อนเริ่มทำงาน และโปรแกรมของเราจะแสดงความคืบหน้าว่าโหลดข้อมูลไปเท่าไหร่แล้วเป็นเปอร์เซนต์จาก 1 - 100% โดยค่าของเปอร์เซนต์จะแสดงบนบรรทัดเดิมด้วยฟังก์ชัน process.stdout.write
let percent = 0;
let buffer = "";
ในตอนแรกเราได้ประกาศตัวแปร percent
สำหรับเก็บความคืบหน้าของการดาวน์โหลด ตัวแปร buffer
สำหรับเก็บค่าของ String ที่ถูกแสดงผลไปก่อนหน้า เพื่อที่ใช้มันในการถอย Cursor กลับตามความยาวของ String ก่อนหน้า ในการแสดงผลครั้งถัดไป
let timerId = setInterval(function () {
...
percent++;
}, 40);
เราได้ใช้ฟังก์ชัน setInterval
เพื่อรันโค้ดในฟังก์ชัน Callback ทุกๆ 40 มิลิวินาที เพิื่ออัพเดทความคืบหน้าของการดาวน์โหลดขึ้นทีละ 1% ฟังก์ชันนี้ส่งค่ากลับเป็น timerId
ที่เราสามารถใช้ยกเลิก Timer เมื่อการดาวน์โหลดสิ้นสุดที่ 100% ได้
process.stdout.write("\b".repeat(buffer.length));
ทุุกๆ ครั้งก่อนที่จะมีการแสดงค่าเปอร์เซนต์ความคืบหน้าของการดาวน์โหลดปัจจุบัน เราได้ถอย Cursor กลับไปยังตำแหน่งแรกเพื่อให้การแสดงผลเขียนทับในบรรทัดเดิม
if (percent >= 100) {
clearInterval(timerId);
process.stdout.write("100% Completed\n");
console.log("The system has been started");
return;
}
นี่เป็นเงื่อนไขเมื่อการดาวน์โหลดเสร็จสิ้น เราได้ยกเลิกการทำงานของ timerId ด้วยฟังก์ชัน clearInterval
และแสดงข้อความว่าการดาวน์โหลดสำเร็จ และจบการทำงานของฟังก์ชันด้วยคำสั่ง return
buffer = "Loading " + percent + "%";
process.stdout.write(buffer);
percent++;
ในขณะที่การดาวน์โหลดยังไม่ถึง 100% เราได้แสดงความคืบหน้าของการดาวน์โหลดปัจจุบันด้วยฟังก์ชัน process.stdout.write
เพื่อไม่ให้ Cursor ขึ้นบรรทัดใหม่ นั่นจะทำให้เราสามารถย้าย Cursor ไปยังตำแหน่งแรกของบรรทัดด้วยตัวอักษรพิเศษ "\b"
เพื่อแสดงข้อความบนบรรทัดเดิมได้
หมายเหตุ: ฟังก์ชัน
setInterval
และsetTimeout
นั้นเป็นฟังก์ชันสำหรับการเขียนโปรแกรมเพื่อให้ทำงานแบบ Asynchronous ซึ่งไม่ได้ครอบคลุมในบทเรียนของเรา
การรับค่าผ่านทางคีย์บอร์ด (Node.js)
ในการเขียนโปรแกรมภาษา JavaScript บน Node.js นั้น เราสามารถรับค่าจากทางคีย์บอร์ดเข้ามาใช้ในโปรแกรมของเราได้โดยการใช้งานฟังก์ชันจากโมดูล readline
นี่เป็นตัวอย่างที่ง่ายที่สุดในการรับค่าจากทางคีย์บอร์ดผ่าน Command line ในภาษา JavaScript
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("Enter your name: ", function (answer) {
console.log("Hello " + answer + "!");
rl.close();
});
และนี่เป็นผลลัพธ์เมื่อเรารันโปรแกรม
Enter your name: Mateo
Hello Mateo!
โปรแกรมจะแสดงคำถามจากพารามิเตอร์แรกของฟังก์ชัน question
และรอจนกว่าเราจะกรอกค่าและกด Enter และค่าที่รับได้จะถูกส่งเข้าไปยังฟังก์ชัน Callback ผ่านตัวแปร answer
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
ในตอนแรกเป็นการนำเข้าโมดูล readline
ด้วยเมธอด require
หลังจากนั้นสร้างออบเจ็ค Interface สำหรับการรับค่าและการแสดงผลที่เชื่อมต่อกับ stdin และ stdout ซึ่งก็คือคีย์บอร์ดและหน้าจอตามลำดับ
rl.question("Enter your name: ", function (answer) {
console.log("Hello " + answer + "!");
rl.close();
});
จากนั้นเป็นการเรียกใช้งานฟังก์ชัน question
บนออบเจ็ค Interface เพื่อรับค่าหนึ่งบรรทัดจากทางคีย์บอร์ด เมธอดนี้รับพารามิเตอร์สองตัวคือคำถามที่จะแสดงก่อนการรับค่า และฟังก์ชัน Callback ที่จะถูกเรียกใช้งานเมื่อได้รับค่ามาแล้ว
การทำงานของฟังก์ชันนี้เป็นแบบไม่พร้อมกัน (Asynchronous) สิ่งที่เราต้องการทำหลังจากได้รับค่ามาแล้วจะต้องถูกเขียนอยู่ภายในฟังก์ชัน Callback ในบางครั้ง เราอาจต้องการรับค่าอื่นหลังจากที่รับค่าแรกเสร็จแล้ว เช่น หลังจากที่รับชื่อมาแล้ว เราต้องการรับค่าปีเกิดต่อต่อ คำถามคือเราจะทำแบบนั้นได้อย่างไร
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("Enter your name: ", function (answer) {
console.log("Hello " + answer + "!");
rl.question("Enter your birth year: ", function (answer) {
let age = new Date().getFullYear() - Number(answer);
console.log("You're " + age + " years old");
rl.close();
});
});
คำตอบก็คือเราจะต้องเรียกใช้งานเมธอด question
ภายในฟังก์ชัน Callback ของการเรียกเมธอด question
ครั้งแรก และแน่นอนว่าถ้าหากเราต้องการรับค่าที่สามหลังจากนี้ เราก็ต้องเรียกเมธอด question
ซ้อนเข้าไปอีกชั้น
แน่นอนว่าเมื่อมีฟังก์ชัน Callback ซ้อนกันเป็นจำนวนมาก ถึงแม้ว่าโปรแกรมของเราจะยังสามารถทำงานได้ แน่นั่นทำให้เกิด Callback hell ซึ่งมันทำให้โค้ดของเราอ่านยากและดูไม่เป็นระเบียบ
เพื่อแก้ปัญหานี้ เราต้องเปลี่ยนการทำงานของการรับค่าให้เป็นแบบ Synchronous โดยการใช้ Promise
และคำสั่ง async
/await
เข้ามาช่วย นี่จะทำให้การรับค่าด้วยเมธอด question
ทำงานเป็นแบบ synchronous เหมือนกับภาษาที่สนับสนุนการรับค่าจาก Console เช่น ภาษา C หรือภาษา Java
จากตัวอย่างด้านบนเราได้แปลงโค้ดของการรับค่าให้ทำงานแบบ synchronous นี่เป็นโค้ดของโปรแกรม
const readline = require('readline');
function prompt(question) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise(function (resolve, reject) {
rl.question(question, function (answer) {
rl.close();
resolve(answer.trim());
});
});
}
(async function () {
let name = await prompt("Enter your name: ");
console.log("Hello " + name + "!");
let year = await prompt("Enter your birth year: ");
let age = new Date().getFullYear() - Number(year);
console.log("You're " + age + " years old");
let a = Number(await prompt("Enter first number: "));
let b = Number(await prompt("Enter second number: "));
console.log("%d + %d = %d", a, b, a + b);
})();
ในตัวอย่าง เป็นโปรแกรมสำหรับถามชื่อและปีเกิดเหมือนในตัวอย่างก่อนหน้า แต่ในตัวอย่างนี้ เราได้เพิ่มการรับค่าตัวเลขอีกสองตัว เพื่อนำมาหาผลรวมและแสดงมันออกทางหน้าจอ จะเห็นว่าคำสั่งการรับค่าทั้งหมดนั้นอยู่ในระดับเดียวกัน และไม่มีการใช้ฟังก์ชัน Callback ซ้อนกันอีกต่อไป
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
Enter your name: Mateo
Hello Mateo!
Enter your birth year: 1988
You're 32 years old
Enter first number: 5
Enter second number: 8
5 + 8 = 13
ตอนนี้โปรแกรมถามให้เรากรอกค่ากรอกค่าจากทางคีย์บอร์ด 4 ครั้งและการทำงานเป็นไปตามลำดับ
สิ่งใหม่ที่คุณเห็นในตัวอย่างนี้ก็คือการใช้งานคลาส Promise
และคำสั่ง async
/await
ในภาษา JavaScript อย่างไรก็ตาม เนื้อหาเหล่านี้เป็นเทคนิคการเขียนโปรแกรมขั้นสูง ดังนั้นเราจะอธิบายการทำงานของมันแบบอย่างง่ายที่สุด
function prompt(question) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise(function (resolve, reject) {
rl.question(question, function (answer) {
rl.close();
resolve(answer);
});
});
}
เราได้สร้างฟังก์ชัน prompt
สำหรับรับค่าจากทางคีย์บอร์ด ฟังก์ชันนี้ส่งค่ากลับเป็นออบเจ็คของ Promise ซึ่งรับฟังก์ชัน Callback ที่มีพารามิเตอร์เป็นฟังก์ชันสองตัวคือ resolve
และ reject
ซึ่งในตอนนี้เราจะสนใจแค่ฟังก์ชัน resolve
rl.question(question, function (answer) {
rl.close();
resolve(answer);
});
ภายในฟังก์ชัน Callback ของ Promise เราได้เรียกใช้เมธอด question
เพื่อรับค่าจากทางคีย์บอร์ด และเช่นเดิมการทำงานในฟังก์ชันนี้เป็นแบบ Asynchronous ซึ่งไม่สำคัญแล้วในตอนนี้ แต่สิ่งหนึ่งที่เรารู้คือเมื่อการรับค่าเสร็จสิ้น (ปุ่ม Enter ถูกกด) ฟังก์ชัน Callback ของเมธอด question
ส่งค่าที่รับเข้ามาผ่านทางพารามิเตอร์ answer
resolve(answer);
ตอนนี้เราได้ค่าที่รับมาจากคีย์บอร์ดแล้ว สิ่งสุดท้ายที่เราต้องทำคือจบการทำงานของ Promise ดังนั้นเราเรียกใช้ฟังก์ชัน resolve
โดยส่งค่าในตัวแปร answer
เข้าไปในฟังก์ชันเพื่อเป็นผลสำเร็จของ Promise
let name = await prompt("Enter your name: ");
หลังจากนั้นเราเรียกใช้งานเมธอด prompt
เพื่อรับค่าตามปกติ ตอนนี้สังเกตว่าจะมีคำสั่ง await
ก่อนชื่อของเมธอดด้วย คำสั่งนี้จะทำให้โค้ดบรรทัดนี้รอการทำงานจากฟังก์ชัน prompt
จนกว่า Promise จะทำการส่งค่ากลับมาด้วยคำสั่ง resolve(answer)
นั่นเอง
// This line instructs promise to return value to `await prompt`
resolve(answer);
...
// Pause execution and wait for answer
let name = await prompt("Enter your name: ");
หรือกล่าวอีกนัยหนึ่ง await prompt
จะหยุดเพื่อรอให้การทำงานในฟังก์ชัน prompt
เสร็จก่อนจนกว่า resolve(answer)
จะถูกเรียก นั่นทำให้การทำงานในฟังก์ชัน prompt
จะส่งผลลัพธ์เป็น answer
กลับมาออกมา นั่นทำให้เราสามารถประกาศตัวแปร name
มารับค่าได้เลย
(async function () {
...
})();
สุดท้ายเราได้สร้างฟังก์ชัน Anonymous ขึ้นมาและเรียกใช้งานมัน เหตุผลที่เราทำเช่นนี้ก็เพราะว่าการใช้งานคำสั่ง await
จะสามารถใช้ได้ภายในฟังก์ชันที่เป็น async
เท่านั้น เราสามารถสร้างมันด้วยการใส่คำสั่ง async
นำหน้าคำสั่ง function
เพื่อบอกว่าฟังก์ชันนี้มีการทำงานแบบ Asynchronous อยู่ภายใน และเราเปลี่ยนการทำงานมันให้เป็นแบบ Synchronous
การรับค่าจาก Command line อาร์กิวเมนต์
ในการเขียนภาษา JavaScript บน Node.js เราสามารถส่งอาร์กิวเมนต์ผ่าน Command line เพื่อนำไปใช้งานในโปรแกรมได้ เราสามารถเข้าถึงอาร์กิวเมนต์ที่ส่งเข้าไปได้ทางอาเรย์ process.argv
ซึ่งเป็นตัวแปรที่ให้มาโดย Node.js
ยกตัวอย่างเช่น เราต้องการส่งค่า Metin
และ 5
เข้าไปในโปรแกรมของเรา ดังนั้นในตอนรันโปรแกรม เราสามารถส่งอาร์กิวเมนต์เพิ่มได้หลังจากชื่อของไฟล์ และคั่นแต่ละอาร์กิวเมนต์ด้วยช่องว่าง
node command_line_argv.js Metin 5
และนี่เป็นวิธีที่เรารับเอาค่าอาร์กิวเมนต์ดังกล่าวภายในโปรแกรม
console.log(process.argv);
console.log("Node: " + process.argv[0]);
console.log("File: " + process.argv[1]);
console.log("Param 1: " + process.argv[2]);
console.log("Param 2: " + process.argv[3]);
ในตัวอย่าง เป็นการเข้าถึงค่าที่ส่งผ่าน Command line เข้ามาในตอนรันโปรแกรม เราสามารถเข้าถึงได้จากตัวแปรอาเรย์ process.argv
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
Node: C:\Program Files\nodejs\node.exe
File: C:\JavaScript\command_line_argv.js
Param 1: Metin
Param 2: 5
และอย่างที่คุณเห็น อาร์กิวเมนต์ตัวแรกในอาเรย์นั้นจะเป็นที่อยู่ของไฟล์ Node.js และอาร์กิวเมนต์ตัวที่สองจะเป็นที่อยู่ของไฟล์โปรแกรมที่กำลังทำงานอยู่ในตอนนี้เสมอ
console.log("Param 1: " + process.argv[2]);
console.log("Param 2: " + process.argv[3]);
ดังนั้นเพื่อเข้าถึงค่าอาร์กิวเมนต์ที่เราต้องการจริงๆ เราจะต้องเริ่มอ่านค่าจาก Index ตำแหน่งที่สองของอาเรย์
เนื่องจากแต่ละอาร์กิวเมนต์ที่ส่งเข้าไปผ่าน Command line นั้นจะคั่นด้วยเว้นวรรค ถ้าหากคุณต้องการส่งค่าของ String ที่มีเว้นวรรคด้วย คุณสามารถครอบมันด้วยเครื่องหมาย Double quote ("
) นั่นจะทำให้ข้อความทั้งหมดภายในถูกรวมเป็นอาร์กิวเมนต์เดียวกัน ยกตัวอย่างเช่น
node string_argv.js 5 "Hello World!"
ในคำสั่งการรันโปรแกรม string_argv.js
ด้านบนนั้นจะส่งข้อความ "Hello World!"
และเราสามารถรับได้ภายในโปรแกรมได้ดังนี้
let loop = Number(process.argv[2]);
let message = process.argv[3];
for (let i = 0; i < loop; i++) {
console.log("%d: %s", i + 1, message);
}
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
1: Hello World!
2: Hello World!
3: Hello World!
4: Hello World!
5: Hello World!
หมายเหตุ: ค่าที่ถูกส่งผ่าน Command line อาร์กิวเมนต์จะเป็น String เสมอ ดังนั้นหากเราต้องการนำมันไปใช้ในรูปแบบอื่น เช่น ตัวเลข เราจะต้องแปลงเป็นตัวเลขด้วยฟังก์ชัน
Number
ก่อน
Escape characters
เนื้อหาสำหรับอ่านเพิ่มเติมเกี่ยวกับการแสดงผลในภาษา JavaScript คือ Escape characters; Escape character คือตัวอักษรพิเศษที่ไม่สามารถแสดงเป็นตัวอักษรในโค้ดของโปรแกรมได้ อาจเป็นเพราะว่ามันเป็นตัวอักษรที่เป็นส่วนหนึ่งของไวยากรณ์ของภาษาหรืออื่นๆ
ยกตัวอย่างเช่นเพื่อแสดงผลการขึ้นบรรทัดใหม่ภายในข้อความ เราต้องใช้ตัวอักษร "\n"
หรือการแสดงแท็บ เราสามารถใช้ตัวอักษร "\t"
ซึ่งตัวอักษรเหล่านี้เรียกว่า Escape character นี่เป็นตัวอย่าง
console.log("ID\tNAME\n1\tMetin\n2\tMateo");
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
ID NAME
1 Metin
2 Mateo
ถ้าหากต้องการ คุณสามารถเรียนรู้เกี่ยวกับมันได้ที่บท Escape characters ในภาษา JavaScript
ฟังก์ชันอื่นๆ ในเนมสเปซ console
นอกจากฟังก์ัชัน console.log
ที่เราสามารถใช้แสดงผลออกทางหน้าจอแล้ว ในภาษา JavaScript ยังมีฟังก์ชันอื่นๆ ที่อยู่ในในเนมสเปซ console
ด้วยเช่นกัน เช่น ฟังก์ชัน console.error
ใช้สำหรับแสดงข้อความที่บอกว่านี่เป็นข้อผิดพลาดที่เกิดขึ้น
นี่เป็นตัวอย่างการใช้งาน
try {
hello()
} catch(e) {
console.error(e.message);
}
เมื่อเรารันโค้ดนี้จะทำให้โปรแกรมเกิดข้อพลาดขึ้น และเราแสดงผลข้อผิดพลาดดังกล่าวด้วยฟังก์ชัน console.error
ฟังก์ชันนี้มีประโยชน์และมันใช้สำหรับแยกข้อความที่เป็นข้อผิดพลาดออกจากข้อความปกติ ซึ่งในเว็บเบราวน์เซอร์หรือ Console ที่สนับสนุนการแสดงผลแบบมีสี ฟังก์ชันนี้จะแสดงข้อความเป็นสีแดง นั่นจะช่วยให้เราสามารถสังเกตเห็นได้ง่ายเมื่อเกิดข้อผิดพลาดขึ้น
สำหรับฟังก์ชันทั้งหมดคุณสามารถดูได้ที่ Console Web APIs; อย่างไรก็ตาม บางฟังก์ชันอาจจะทำงานแตกต่างกันในแต่ละ Host environment
ในบทนี้ คุณได้เรียนรู้เกี่ยวกับการรับค่าและการแสดงผลในภาษา JavaScript เราได้พูดถึงการใช้งานฟังก์ชันการแสดงผลพื้นฐานอย่าง console.log
การจัดรูปแบบการแสดงผล การรับค่าจากทางคีย์บอร์ดและผ่าน Command line อาร์กิวเมนต์ ซึ่งเป็นการรับค่าที่สามารถทำได้บน Node.js เท่านั้น