เชี่ยวชาญตัวดำเนินการ nullish coalescing (??) ของ JavaScript เพื่อการกำหนดค่าเริ่มต้นที่สะอาดและมีประสิทธิภาพยิ่งขึ้น เรียนรู้ความแตกต่างจากตัวดำเนินการ OR (||) พร้อมดูตัวอย่างการใช้งานจริง
JavaScript Nullish Coalescing: คู่มือฉบับสมบูรณ์สำหรับการกำหนดค่าเริ่มต้น
ใน JavaScript การกำหนดค่าเริ่มต้นเป็นงานที่ทำกันโดยทั่วไป ตามปกติแล้ว นักพัฒนาจะใช้ตัวดำเนินการ OR (||
) เพื่อจุดประสงค์นี้ อย่างไรก็ตาม ตัวดำเนินการ nullish coalescing (??
) ซึ่งเปิดตัวใน ECMAScript 2020 ได้มอบวิธีการที่แม่นยำและเชื่อถือได้มากขึ้นในการจัดการกับการกำหนดค่าเริ่มต้น โดยเฉพาะอย่างยิ่งเมื่อต้องจัดการกับค่า null
หรือ undefined
คู่มือนี้จะเจาะลึกเกี่ยวกับตัวดำเนินการ nullish coalescing โดยสำรวจไวยากรณ์ พฤติกรรม ความแตกต่างจากตัวดำเนินการ OR และกรณีการใช้งานจริง
Nullish Coalescing คืออะไร?
ตัวดำเนินการ nullish coalescing (??
) เป็นตัวดำเนินการทางตรรกะที่จะคืนค่าตัวถูกดำเนินการฝั่งขวา (right-hand side operand) เมื่อตัวถูกดำเนินการฝั่งซ้าย (left-hand side operand) เป็น null
หรือ undefined
มิฉะนั้นจะคืนค่าตัวถูกดำเนินการฝั่งซ้าย พูดง่ายๆ ก็คือ มันจะให้ค่าเริ่มต้นก็ต่อเมื่อตัวแปรเป็น null
หรือ undefined
อย่างเคร่งครัดเท่านั้น
ไวยากรณ์ (Syntax)
ไวยากรณ์สำหรับตัวดำเนินการ nullish coalescing นั้นตรงไปตรงมา:
leftOperand ?? rightOperand
ในที่นี้ leftOperand
คือตัวแปรหรือนิพจน์ที่คุณต้องการตรวจสอบว่าเป็น null
หรือ undefined
หรือไม่ และ rightOperand
คือค่าเริ่มต้นที่คุณต้องการกำหนดหาก leftOperand
เป็น null
หรือ undefined
จริงๆ
ตัวอย่าง
พิจารณาตัวอย่างต่อไปนี้:
const username = null ?? "Guest";
console.log(username); // ผลลัพธ์: Guest
const age = undefined ?? 25;
console.log(age); // ผลลัพธ์: 25
const city = "London" ?? "Unknown";
console.log(city); // ผลลัพธ์: London
ในตัวอย่างนี้ username
ถูกกำหนดค่าเริ่มต้นเป็น "Guest" เพราะค่าเริ่มต้นเป็น null
ในทำนองเดียวกัน age
ถูกกำหนดเป็น 25 เพราะเริ่มต้นเป็น undefined
อย่างไรก็ตาม city
ยังคงค่าเดิมคือ "London" เพราะมันไม่ใช่ทั้ง null
และ undefined
ค่า Nullish กับค่า Falsy
การทำความเข้าใจความแตกต่างระหว่างค่า nullish และค่า falsy ใน JavaScript เป็นสิ่งสำคัญอย่างยิ่ง ค่า nullish คือค่าที่เป็น null
หรือ undefined
ส่วนค่า falsy คือค่าที่ถือว่าเป็นเท็จเมื่อพบในบริบทของบูลีน (Boolean) ค่า Falsy ประกอบด้วย:
null
undefined
0
(ศูนย์)NaN
(ไม่ใช่ตัวเลข)''
(สตริงว่าง)false
ข้อแตกต่างที่สำคัญคือตัวดำเนินการ nullish coalescing จะตรวจสอบเฉพาะ null
หรือ undefined
เท่านั้น ในขณะที่ตัวดำเนินการ OR (||
) จะตรวจสอบค่า falsy ใดๆ
ความแตกต่างระหว่าง ??
และ ||
ตัวดำเนินการ OR (||
) เป็นตัวดำเนินการตรรกะ OR ที่จะคืนค่าตัวถูกดำเนินการฝั่งขวาหากตัวถูกดำเนินการฝั่งซ้ายเป็นค่า falsy แม้ว่าจะสามารถใช้สำหรับการกำหนดค่าเริ่มต้นได้ แต่ก็อาจนำไปสู่พฤติกรรมที่ไม่คาดคิดเมื่อต้องจัดการกับค่าเช่น 0
หรือสตริงว่าง
ตัวอย่าง: ข้อควรระวังของ ||
const quantity = 0 || 10; // เราตั้งใจให้มีค่าเริ่มต้นเป็น 10 หากไม่มี quantity
console.log(quantity); // ผลลัพธ์: 10 (ไม่คาดคิด!) เพราะ 0 เป็นค่า falsy
const text = '' || 'Default Text'; //เราตั้งใจให้มีข้อความเริ่มต้นหากไม่มี text
console.log(text); // ผลลัพธ์: Default Text (ไม่คาดคิด!) เพราะ '' เป็นค่า falsy
ในตัวอย่างแรก เราตั้งใจจะกำหนดค่าเริ่มต้นของ quantity เป็น 10 ก็ต่อเมื่อ quantity
หายไป (null
หรือ undefined
) เท่านั้น อย่างไรก็ตาม เนื่องจาก 0
เป็นค่า falsy ตัวดำเนินการ OR จึงกำหนดค่าเริ่มต้นอย่างไม่ถูกต้อง ในทำนองเดียวกัน สตริงว่างทำให้ข้อความเริ่มต้นถูกแสดงแม้ว่าสตริงนั้นจะมีอยู่ (แต่เป็นสตริงว่าง) ก็ตาม
การใช้ ??
เพื่อความแม่นยำ
ลองเขียนตัวอย่างก่อนหน้านี้ใหม่โดยใช้ตัวดำเนินการ nullish coalescing:
const quantity = 0 ?? 10;
console.log(quantity); // ผลลัพธ์: 0 (ถูกต้อง!)
const text = '' ?? 'Default Text';
console.log(text); // ผลลัพธ์: '' (ถูกต้อง!)
ตอนนี้ ผลลัพธ์เป็นไปตามที่คาดไว้ ตัวดำเนินการ nullish coalescing จะตรวจสอบเฉพาะ null
หรือ undefined
เท่านั้น ดังนั้น 0
และ ''
จึงถือเป็นค่าที่ถูกต้อง และค่าดั้งเดิมของมันจึงถูกคงไว้
กรณีการใช้งานสำหรับ Nullish Coalescing
ตัวดำเนินการ nullish coalescing มีประโยชน์ในสถานการณ์ต่างๆ ที่คุณต้องการให้ค่าเริ่มต้นก็ต่อเมื่อตัวแปรเป็น null
หรือ undefined
อย่างเคร่งครัดเท่านั้น นี่คือกรณีการใช้งานทั่วไปบางส่วน:
1. การจัดการพารามิเตอร์ของฟังก์ชันที่เป็นทางเลือก (Optional)
เมื่อกำหนดฟังก์ชันที่มีพารามิเตอร์ที่เป็นทางเลือก คุณสามารถใช้ตัวดำเนินการ nullish coalescing เพื่อกำหนดค่าเริ่มต้นหากไม่มีการส่งพารามิเตอร์เข้ามา
function greet(name, greeting) {
const userName = name ?? "User";
const userGreeting = greeting ?? "Hello";
console.log(`${userGreeting}, ${userName}!`);
}
greet(); // ผลลัพธ์: Hello, User!
greet("Alice"); // ผลลัพธ์: Hello, Alice!
greet("Bob", "Greetings"); // ผลลัพธ์: Greetings, Bob!
2. การตั้งค่าตัวเลือกการกำหนดค่าเริ่มต้น
เมื่อทำงานกับอ็อบเจ็กต์การกำหนดค่า (configuration objects) คุณสามารถใช้ตัวดำเนินการ nullish coalescing เพื่อให้แน่ใจว่ามีการใช้ค่าเริ่มต้นหากตัวเลือกการกำหนดค่าบางอย่างไม่ได้ถูกระบุไว้
const config = {
timeout: 5000,
retries: 3
};
function fetchData(options) {
const timeout = options.timeout ?? 10000; // ค่า timeout เริ่มต้น 10 วินาที
const retries = options.retries ?? 5; // ค่า retries เริ่มต้น 5 ครั้ง
console.log(`Timeout: ${timeout}, Retries: ${retries}`);
}
fetchData(config); // ผลลัพธ์: Timeout: 5000, Retries: 3
fetchData({}); // ผลลัพธ์: Timeout: 10000, Retries: 5
fetchData({timeout:null, retries: undefined}); // ผลลัพธ์: Timeout: 10000, Retries: 5
3. การเข้าถึงคุณสมบัติของอ็อบเจ็กต์ที่ซ้อนกัน
เมื่อเข้าถึงคุณสมบัติของอ็อบเจ็กต์ที่ซ้อนกัน สามารถใช้ตัวดำเนินการ nullish coalescing ร่วมกับ optional chaining (?.
) เพื่อกำหนดค่าเริ่มต้นหากคุณสมบัติระดับกลางใดๆ เป็น null
หรือ undefined
const user = {
profile: {
address: {
city: "New York"
}
}
};
const cityName = user?.profile?.address?.city ?? "Unknown";
console.log(cityName); // ผลลัพธ์: New York
const unknownUser = {};
const unknownCityName = unknownUser?.profile?.address?.city ?? "Unknown";
console.log(unknownCityName); // ผลลัพธ์: Unknown
4. การทำงานกับ API และข้อมูลภายนอก
เมื่อดึงข้อมูลจาก API หรือแหล่งข้อมูลภายนอก สามารถใช้ตัวดำเนินการ nullish coalescing เพื่อกำหนดค่าเริ่มต้นหากฟิลด์ข้อมูลบางฟิลด์หายไปหรือมีค่าเป็น null
หรือ undefined
ลองพิจารณาการดึงข้อมูลผู้ใช้จากภูมิภาคต่างๆ สมมติว่าบางภูมิภาคอาจไม่รวมฟิลด์ `country` ในข้อมูลผู้ใช้ของพวกเขา
async function getUserData(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
const data = await response.json();
const country = data.country ?? "Unknown Country";
const timezone = data.timezone ?? "UTC";
console.log(`User is from: ${country}, Timezone: ${timezone}`);
} catch (error) {
console.error("Error fetching user data:", error);
}
}
// จำลองการตอบสนอง API ที่แตกต่างกัน:
const userWithCountry = { name: "John", country: "USA", timezone: "EST" };
const userWithoutCountry = { name: "Jane", timezone: "GMT" };
// เพื่อทดสอบสิ่งนี้ คุณจะต้องมี API จริงหรือ mock fetch
// เพื่อวัตถุประสงค์ในการสาธิต ลองจำลองการตอบสนอง:
global.fetch = async (url) => {
if (url.includes("123")) {
return { json: async () => userWithCountry };
} else if (url.includes("456")) {
return { json: async () => userWithoutCountry };
}
throw new Error("Unexpected URL");
};
getUserData(123); // ผลลัพธ์: User is from: USA, Timezone: EST
getUserData(456); // ผลลัพธ์: User is from: Unknown Country, Timezone: GMT
ลำดับความสำคัญของตัวดำเนินการ (Operator Precedence)
ตัวดำเนินการ nullish coalescing มีลำดับความสำคัญของตัวดำเนินการที่ค่อนข้างต่ำ โดยต่ำกว่าตัวดำเนินการ OR (||
) และ AND (&&
) ดังนั้น เมื่อใช้ตัวดำเนินการ nullish coalescing ร่วมกับตัวดำเนินการทางตรรกะอื่นๆ จำเป็นต้องใช้วงเล็บเพื่อกำหนดลำดับการดำเนินการอย่างชัดเจน การไม่ทำเช่นนั้นอาจส่งผลให้เกิดข้อผิดพลาดทางไวยากรณ์ (syntax errors) หรือพฤติกรรมที่ไม่คาดคิด
ตัวอย่าง: การใช้วงเล็บเพื่อความชัดเจน
// ไม่มีวงเล็บ (SyntaxError)
// const result = false || null ?? "Default"; // SyntaxError: Unexpected token '??'
// มีวงเล็บ (ถูกต้อง)
const result = false || (null ?? "Default");
console.log(result); // ผลลัพธ์: Default
const anotherResult = (false || null) ?? "Default";
console.log(anotherResult); // ผลลัพธ์: null
ในตัวอย่างแรก การไม่ใส่วงเล็บส่งผลให้เกิด SyntaxError
เนื่องจาก JavaScript engine ไม่สามารถระบุลำดับการดำเนินการที่ต้องการได้ การเพิ่มวงเล็บเป็นการบอก engine อย่างชัดเจนให้ประเมินตัวดำเนินการ nullish coalescing ก่อน ตัวอย่างที่สองนั้นถูกต้อง แต่ผลลัพธ์แตกต่างออกไปเนื่องจากนิพจน์ ||
ถูกประเมินก่อน
ความเข้ากันได้กับเบราว์เซอร์ (Browser Compatibility)
ตัวดำเนินการ nullish coalescing (??
) เป็นฟีเจอร์ที่ค่อนข้างใหม่ ดังนั้นจึงเป็นเรื่องสำคัญที่ต้องพิจารณาความเข้ากันได้กับเบราว์เซอร์ โดยเฉพาะอย่างยิ่งหากคุณตั้งเป้าไปที่เบราว์เซอร์รุ่นเก่า เบราว์เซอร์สมัยใหม่ส่วนใหญ่รองรับตัวดำเนินการ nullish coalescing ได้แก่:
- Chrome 80+
- Firefox 72+
- Safari 13.1+
- Edge 80+
- Node.js 14+
หากคุณต้องการรองรับเบราว์เซอร์รุ่นเก่า คุณสามารถใช้ transpiler เช่น Babel เพื่อแปลงโค้ดของคุณเป็น JavaScript เวอร์ชันที่เข้ากันได้ Babel จะแปลงตัวดำเนินการ ??
เป็นโค้ด JavaScript ที่เทียบเท่าซึ่งทำงานได้ในสภาพแวดล้อมที่เก่ากว่า
แนวทางปฏิบัติที่ดีที่สุด (Best Practices)
นี่คือแนวทางปฏิบัติที่ดีที่สุดบางประการสำหรับการใช้ตัวดำเนินการ nullish coalescing อย่างมีประสิทธิภาพ:
- ใช้
??
สำหรับการตรวจสอบค่า nullish: ใช้ตัวดำเนินการ nullish coalescing (??
) เมื่อคุณต้องการให้ค่าเริ่มต้นเฉพาะเมื่อตัวแปรเป็นnull
หรือundefined
เท่านั้น - ใช้วงเล็บสำหรับนิพจน์ที่ซับซ้อน: เมื่อใช้ตัวดำเนินการ nullish coalescing ร่วมกับตัวดำเนินการทางตรรกะอื่นๆ ให้ใช้วงเล็บเพื่อกำหนดลำดับการดำเนินการอย่างชัดเจน
- พิจารณาความเข้ากันได้กับเบราว์เซอร์: ตรวจสอบความเข้ากันได้กับเบราว์เซอร์และใช้ transpiler หากจำเป็นต้องรองรับเบราว์เซอร์รุ่นเก่า
- ใช้อย่างสม่ำเสมอ: นำ
??
มาใช้ในกรณีที่เหมาะสมเพื่อให้มีรูปแบบการเขียนโค้ดที่คาดเดาได้ง่ายทั่วทั้งโปรเจกต์ - ใช้ร่วมกับ optional chaining: ใช้
??
ร่วมกับ optional chaining?.
เพื่อเข้าถึงและกำหนดค่าเริ่มต้นให้กับคุณสมบัติที่ซ้อนกันของอ็อบเจ็กต์ได้อย่างปลอดภัย
ข้อควรพิจารณาในระดับสากล (Global Considerations)
เมื่อพัฒนาสำหรับผู้ใช้ทั่วโลก ให้พิจารณาประเด็นต่อไปนี้ที่เกี่ยวข้องกับการกำหนดค่าเริ่มต้น:
- การปรับให้เข้ากับท้องถิ่น (Localization): ค่าเริ่มต้นอาจต้องถูกปรับให้เข้ากับท้องถิ่นตามภาษาหรือภูมิภาคของผู้ใช้ ตัวอย่างเช่น สัญลักษณ์สกุลเงินเริ่มต้นหรือรูปแบบวันที่
- บรรทัดฐานทางวัฒนธรรม (Cultural Norms): ค่าเริ่มต้นบางอย่างอาจต้องปรับตามบรรทัดฐานทางวัฒนธรรม ตัวอย่างเช่น ข้อความทักทายเริ่มต้นอาจต้องแตกต่างกันไปในแต่ละวัฒนธรรม
- การเข้าถึงได้ (Accessibility): ตรวจสอบให้แน่ใจว่าค่าเริ่มต้นสามารถเข้าถึงและเข้าใจได้สำหรับผู้ใช้ที่มีความพิการ จัดเตรียมป้ายกำกับที่ชัดเจนและสื่อความหมายสำหรับค่าเริ่มต้นในส่วนติดต่อผู้ใช้
- เขตเวลาและวันที่ (Timezones and Dates): เมื่อทำงานกับวันที่และเวลา ให้ใช้เขตเวลาและรูปแบบวันที่ที่เหมาะสมเพื่อให้แน่ใจว่าค่าเริ่มต้นจะแสดงให้กับผู้ใช้ในภูมิภาคต่างๆ ได้อย่างถูกต้อง
ตัวอย่าง: การปรับให้เข้ากับท้องถิ่นด้วย Nullish Coalescing
สมมติว่าคุณต้องการแสดงข้อความต้อนรับเริ่มต้นในภาษาต่างๆ ตาม locale ของผู้ใช้ คุณสามารถใช้ตัวดำเนินการ nullish coalescing เพื่อให้ข้อความเริ่มต้นหากไม่มีข้อความที่แปลไว้
function getWelcomeMessage(locale) {
const localizedMessages = {
en: "Welcome!",
fr: "Bienvenue !",
de: "Willkommen!"
};
const message = localizedMessages[locale] ?? "Welcome!"; // ใช้ภาษาอังกฤษเป็นค่าเริ่มต้นหากไม่พบ locale
return message;
}
console.log(getWelcomeMessage("fr")); // ผลลัพธ์: Bienvenue !
console.log(getWelcomeMessage("es")); // ผลลัพธ์: Welcome! (ใช้ค่าเริ่มต้นเป็นภาษาอังกฤษ)
บทสรุป
ตัวดำเนินการ nullish coalescing (??
) เป็นส่วนเสริมที่มีค่าสำหรับภาษา JavaScript มันมอบวิธีการที่แม่นยำและเชื่อถือได้มากขึ้นในการกำหนดค่าเริ่มต้นเมื่อเทียบกับตัวดำเนินการ OR (||
) โดยเฉพาะอย่างยิ่งเมื่อต้องจัดการกับค่าเช่น 0
หรือสตริงว่าง การทำความเข้าใจไวยากรณ์ พฤติกรรม และกรณีการใช้งาน จะช่วยให้คุณสามารถเขียนโค้ดที่สะอาดและบำรุงรักษาง่ายขึ้น ซึ่งจัดการกับการกำหนดค่าเริ่มต้นได้อย่างแม่นยำ อย่าลืมพิจารณาความเข้ากันได้กับเบราว์เซอร์ ลำดับความสำคัญของตัวดำเนินการ และข้อควรพิจารณาในระดับสากลเมื่อใช้ตัวดำเนินการ nullish coalescing ในโปรเจกต์ของคุณ
โดยการปฏิบัติตามแนวทางที่ดีที่สุดที่ระบุไว้ในคู่มือนี้ คุณจะสามารถใช้ประโยชน์จากตัวดำเนินการ nullish coalescing ได้อย่างมีประสิทธิภาพเพื่อปรับปรุงคุณภาพและความน่าเชื่อถือของโค้ด JavaScript ของคุณ ทำให้โค้ดมีความแข็งแกร่งและเข้าใจง่ายขึ้น โปรดจำไว้เสมอว่าต้องให้ความสำคัญกับความชัดเจนและการบำรุงรักษาในโค้ดของคุณ และตัวดำเนินการ nullish coalescing สามารถเป็นเครื่องมือที่ทรงพลังในการบรรลุเป้าหมายเหล่านี้ได้