JavaScript
Object
in operator
เรียนรู้ `in` operator — เช็กว่า key มีอยู่ใน object หรือไม่, ความต่างระหว่าง `in` กับ `!== undefined`, guard pattern ด้วย `if + in`, และการใช้ `in` กับ dynamic key
`in` operator คืออะไร — ใช้เช็กว่า key มีอยู่ใน object หรือไม่
`in` operator ใช้ตรวจสอบว่า key (ชื่อ property) มีอยู่ใน object หรือไม่ — เขียน `"key" in object` แล้วได้ผลลัพธ์เป็น `true` หรือ `false` เป็นวิธีเดียวที่เช็ก**การมีอยู่ของ key โดยตรง** — ต่างจากการเช็กค่าด้วย `obj.key !== undefined` ซึ่งอาจให้ผลผิดเมื่อค่านั้นตั้งใจเป็น `undefined`
`in` คืน `true` เมื่อ key มีอยู่ และ `false` เมื่อ key ไม่มี
const user = { name: "สมชาย", age: 28 };
console.log("name" in user); // true — "name" มีอยู่ใน user
console.log("age" in user); // true — "age" มีอยู่ใน user
console.log("email" in user); // false — "email" ไม่มีใน user- **Syntax:** `"key" in object` — key ต้องเป็น string หรือ Symbol
- **คืนค่าเป็น `boolean`** — `true` ถ้า key มีอยู่, `false` ถ้าไม่มี
- **เช็กที่ key ไม่ใช่ที่ value** — ถึง value จะเป็น `undefined` ก็ยังคืน `true` ถ้า key มีอยู่
- **ไม่ throw error** — แม้ object จะเป็น `null` หรือ `undefined` ก็ไม่พัง (แต่จะได้ `TypeError` — ต้องระวัง)
วิธีใช้ `in` — เช็ก key แบบต่าง ๆ
`in` รับ key เป็น string literal หรือตัวแปรก็ได้ — ทำให้ยืดหยุ่นเวลา key มาจากข้อมูลภายนอกหรือการคำนวณ
`in` ใช้กับ string literal โดยตรง, กับ bracket notation, และกับตัวแปรได้ — ไม่ต้องใช้ `""` ตอนใช้ตัวแปร
const product = { name: "เมาส์", price: 590, "in-stock": true };
// 1. string literal โดยตรง
console.log("price" in product); // true
// 2. bracket notation — key มีอักขระพิเศษ
console.log("in-stock" in product); // true
// 3. ตัวแปร — key มาจากตัวแปร
const field = "name";
console.log(field in product); // true
const missing = "brand";
console.log(missing in product); // false
// 4. ใช้ in ใน expression ได้เลย
console.log("discount" in product ? "มีส่วนลด" : "ไม่มีส่วนลด"); // "ไม่มีส่วนลด"**ข้อสังเกต:** ตอนใช้ `in` กับตัวแปร — ใส่ชื่อตัวแปรตรง ๆ โดยไม่ต้องครอบ `""` เพราะ JavaScript จะเอาค่าในตัวแปรมาใช้เป็นชื่อ key
`in` กับ property ที่มีค่าเป็น `undefined` — จุดที่ทำให้ `in` เหนือกว่า `obj.key !== undefined`
**ความต่างสำคัญที่สุด** ระหว่าง `"key" in obj` กับ `obj.key !== undefined`: - `"key" in obj` — เช็กว่า **key มีอยู่ใน object** (ไม่สนใจ value) - `obj.key !== undefined` — เช็กว่า **value ไม่ใช่ `undefined`** (ไม่สนใจว่า key มีหรือไม่มี) เมื่อ key มีอยู่แต่ค่าถูกตั้งเป็น `undefined` — `in` จะคืน `true` แต่ `obj.key !== undefined` จะคืน `false`
เมื่อค่าถูกตั้งเป็น `undefined` โดยตั้งใจ — `in` บอกว่า key มีอยู่ แต่ `!== undefined` กลับบอกว่าไม่มี — `in` แม่นยำกว่าเมื่อต้องการเช็กการมีอยู่ของ key
const config = { debug: undefined, mode: "production" };
// "debug" มีอยู่ — แต่ค่าคือ undefined (ตั้งใจ)
console.log("debug" in config); // true ← key มีอยู่จริง
console.log(config.debug !== undefined); // false ← เช็กที่ value
// "mode" มีอยู่ และมีค่าปกติ — ทั้งคู่ได้ผลตรงกัน
console.log("mode" in config); // true
console.log(config.mode !== undefined); // true
// "secret" ไม่มีเลยใน object — ทั้งคู่ได้ผลตรงกัน
console.log("secret" in config); // false
console.log(config.secret !== undefined); // false- **ใช้ `in`** เมื่อต้องการรู้ว่า key มีอยู่ในโครงสร้าง object หรือไม่ — เช่น เช็กก่อนเพิ่ม, เช็กว่าข้อมูลจาก API มี field นั้นหรือเปล่า
- **ใช้ `!== undefined`** เมื่อแค่ต้องการรู้ว่า value พร้อมใช้งานหรือยัง — แต่ต้องมั่นใจว่าไม่มีกรณีที่ตั้งใจให้ value เป็น `undefined`
- **เลือกผิด → logic พังเงียบ ๆ** — ถ้าใช้ `!== undefined` เช็กแทน `in` ในระบบที่ใช้ `undefined` เป็นค่าที่มีความหมาย จะทำให้คิดว่า key ไม่มีทั้งที่มันมี
ใช้ `in` ร่วมกับ `if` — guard pattern สำหรับตรวจสอบก่อนทำอะไรกับ property
`in` มักใช้ร่วมกับ `if` เพื่อตรวจสอบว่า property มีอยู่ก่อนจะอ่าน เขียน หรือลบ — ป้องกัน error และ logic ผิดพลาด
`if + in` ใช้เช็กก่อนทำอะไรกับ property — ป้องกันทั้ง error (`Cannot read property...`) และ logic ผิดพลาด
const response = { status: "ok", data: { title: "ข่าวด่วน" } };
// guard: ตรวจก่อนเข้าถึง data
if ("data" in response) {
console.log("มี data:", response.data.title); // "มี data: ข่าวด่วน"
} else {
console.log("ไม่มี field data ใน response");
}
// guard + dynamic key
const requiredField = "token";
if (requiredField in response) {
console.log("token:", response[requiredField]); // ไม่ทำงาน — "token" ไม่มี
}
// !(in) — เช็กว่า key ยังไม่มี (guard pattern ใน add)
const newUser = {};
if (!("name" in newUser)) {
newUser.name = "สมศรี";
console.log("เพิ่ม name แล้ว");
}
console.log(newUser.name); // "สมศรี"`in` + `&&` ใช้เช็กหลาย key ก่อนทำงาน — pattern นี้มีประโยชน์มากตอน validate ข้อมูลที่มาจาก form หรือ API
const form = { email: "user@example.com", password: "123456" };
// เช็กว่ามีครบทุก field ที่ต้องการ
if ("email" in form && "password" in form) {
console.log("Form พร้อม submit");
} else {
console.log("Form ไม่ครบ — ขาด field บังคับ");
}
// เช็กหลาย field ด้วยตัวแปร
const requiredFields = ["name", "email", "password"];
const missing = requiredFields.filter(f => !(f in form));
console.log("ขาด:", missing); // ["name"]- **`if ("key" in obj)`** — ทำงานต่อเมื่อ key มีอยู่
- **`if (!("key" in obj))`** — ทำงานต่อเมื่อ key ยังไม่มี (เช่น เพิ่ม property ใหม่)
- **`in` + `&&`** — เช็กหลาย key พร้อมกันก่อนทำงาน
- **`in` + `filter`** — หา key ที่ขาดไปจากข้อมูลภายนอก
ข้อควรรู้ — `in` ตรวจสอบ prototype chain ด้วย และใช้กับ array ได้
`in` ไม่ได้ตรวจสอบเฉพาะ own property — มันตรวจสอบ**ทั้งตัว object และ prototype chain** นี่หมายความว่า `"toString" in {}` จะคืน `true` เพราะ `toString` อยู่ใน `Object.prototype` — ไม่ใช่ own property แต่ `in` มองเห็น นอกจากนี้ `in` ใช้กับ array ได้ — เช็กว่า index มีอยู่ใน array หรือไม่
`in` มองเห็นทั้ง own property และ property ที่ inherit มา — เรื่องนี้สำคัญเมื่อต้องการเช็กเฉพาะ own property (จะเรียน `Object.hasOwn()` ในบทเรียนขั้นสูงต่อไป)
const empty = {};
console.log("toString" in empty); // true — มาจาก Object.prototype
// empty เองไม่มี toString แต่ in มองเห็นใน prototype
const obj = { name: "test" };
console.log("name" in obj); // true — own property
console.log("toString" in obj); // true — inherited`in` กับ array — เช็กว่า index มีค่าแน่ ๆ ไม่ใช่ empty slot — มีประโยชน์น้อยกว่าเช็ก object แต่รู้ไว้มีประโยชน์
const fruits = ["แอปเปิ้ล", "กล้วย", , "ส้ม"]; // index 2 เป็น empty
console.log(0 in fruits); // true — index 0 มีค่า "แอปเปิ้ล"
console.log(1 in fruits); // true — index 1 มีค่า "กล้วย"
console.log(2 in fruits); // false — index 2 เป็น empty slot
console.log(3 in fruits); // true — index 3 มีค่า "ส้ม"
console.log(5 in fruits); // false — index 5 เลย length ไป
// ต่างจากการเช็กด้วย fruits[i]
console.log(fruits[2] !== undefined); // false — ได้ผลตรงกัน
// แต่ในเคสอื่นอาจต่างกันเมื่อ array มีค่า undefined จริง ๆ- **`in` มองเห็น inherited properties** — `"toString" in {}` → `true`
- **ใช้ `in` กับ array** — เช็กว่า index มีค่าหรือเป็น empty slot
- **`in` ไม่เช็ก value** — เช็กที่ key/index ว่ามีอยู่หรือไม่
- **`in` ใช้ Symbol เป็น key ได้** — `Symbol.iterator in []` → `true`