วันนี้ได้ลองให้ Sonarqube scan ดูแล้วเจอ warning Prefer using nullish coalescing operator (??=) instead of an assignment expression, as it is simpler to read.
โดยเฉพาะตัวนี้ ??=
เป็นตัวที่ยังไม่เคยใช้เลย
เอามาเขียนสรุปไว้เหมือนเดิม
ก่อนอื่นเราต้อง เข้าใจ ??
กับ ||
กันก่อน
ใน JavaScript ||
เป็นตัวดำเนินการ OR
ตรรกะ ซึ่งจะคืนค่า true
ถ้ามีค่าใดค่าหนึ่งเป็นจริง
ในขณะที่ ??
เป็นตัวดำเนินการ nullish coalescing
ซึ่งจะคืนค่าทางขวาหากค่าทางซ้ายเป็น null
หรือ undefined
กล่าว คือ ...
|| (OR ตรรกะ)
จะประเมินค่าทางซ้ายก่อน หากค่าทางซ้ายเป็น truthy (เช่น ไม่ใช่ null, undefined, 0, '', NaN, false) จะคืนค่าทางซ้ายทันที หากค่าทางซ้ายเป็น falsy จะประเมินค่าทางขวา และคืนค่าทางขวา
console.log(null || "ค่าเริ่มต้น"); // Output: ค่าเริ่มต้น
console.log(true || "ค่าเริ่มต้น"); // Output: true
ตัวอย่าง ||
?? (Nullish Coalescing)
จะประเมินค่าทางซ้ายก่อน หากค่าทางซ้ายเป็น null หรือ undefined จะคืนค่าทางขวา หากค่าทางซ้ายไม่ใช่ null หรือ undefined จะคืนค่าทางซ้ายทันที.
console.log(null ?? "ค่าเริ่มต้น"); // Output: ค่าเริ่มต้น
console.log(0 ?? "ค่าเริ่มต้น"); // Output: 0
ตัวอย่าง ??
ประโยชน์ของ ??
คือ
- ปลอดภัยกว่า - ไม่ coalesce กับค่า falsy อื่น ๆ
- สั้นกว่า - ไม่ต้องเขียน conditional ยาว ๆ
- ชัดเจนกว่า - แสดงเจตนาที่ต้องการจัดการ null/undefined เท่านั้น
- ลดข้อผิดพลาด - หลีกเลี่ยงการ coalesce ที่ไม่ต้องการ
ความแตกต่างระหว่าง ??
และ ||
ทีนี้เรามาดูข้อแตกต่างกันระหว่าง 2 ตัวนี้กัน โดยจะเน้นไปที่ ค่า falsy
ใน JavaScript ได้แก่ false, 0, "", null, undefined, NaN
Logical OR (||
)
จะไม่ค่อยปลอดภัย เพราะมันจะ coalesce
กับค่า falsy
ทั้งหมด
const result1 = value || "default"
Nullish Coalescing (??
)
จะปลอดภัยกว่า เพราะมันจะ coalesce
เฉพาะ null
และ undefined
เท่านั้น
const result2 = value ?? "default"
มาดูตัวอย่างกัน
ตัวอย่างปัญหาที่เกิดขึ้น
// ❌ ปัญหาเมื่อใช้ ||
function getPort(port: number | null) {
return port || 3000 // ถ้า port = 0 จะได้ 3000 (ผิด!)
}
getPort(0) // ได้ 3000 แทนที่จะเป็น 0
getPort(null) // ได้ 3000 (ถูก)
// ✅ แก้ไขด้วย ??
function getPort(port: number | null) {
return port ?? 3000 // ถ้า port = 0 จะได้ 0 (ถูก!)
}
getPort(0) // ได้ 0 (ถูก)
getPort(null) // ได้ 3000 (ถูก)
ตัวอย่างการใช้งานจริง
// ❌ ไม่ปลอดภัย
const username = user.name || "Anonymous" // ถ้า name = "" จะได้ "Anonymous"
const count = items.length || 0 // ถ้า length = 0 จะได้ 0 (ซ้ำซ้อน)
const isEnabled = config.enabled || false // ถ้า enabled = false จะได้ false (ซ้ำซ้อน)
// ✅ ปลอดภัยกว่า
const username = user.name ?? "Anonymous" // เฉพาะ null/undefined เท่านั้น
const count = items.length ?? 0 // เฉพาะ null/undefined เท่านั้น
const isEnabled = config.enabled ?? false // เฉพาะ null/undefined เท่านั้น
การแทนที่ Conditional Expressions
// ❌ แบบเก่า - ยาวและซับซ้อน
const result = value !== null && value !== undefined ? value : "default"
// ✅ แบบใหม่ - สั้นและชัดเจน
const result = value ?? "default"
และอันสุดท้าย การใช้งาน ??=
let result = null
result ??= "default"