โหมดมืด
บทที่ 03 — Operators: เครื่องหมายคำนวณและเปรียบเทียบ
Operator = "เครื่องหมาย" ที่ใช้ทำอะไรกับข้อมูล — บวก ลบ คูณ เปรียบเทียบ ฯลฯ
บทนี้สอน operator ทุกตัวที่ต้องรู้ พร้อมกับ "กับดัก" ที่ทำให้มือใหม่เขียนบั๊กบ่อย
อ่านจบบทนี้คุณจะ:
- คำนวณเลข เปรียบเทียบค่า ได้ถูกต้อง
- เข้าใจว่าทำไมต้องใช้
===ไม่ใช่==(เรื่องสำคัญมาก) - ใช้ operator สมัยใหม่
??,?.,...ที่ทำให้โค้ดสั้นและปลอดภัย - เข้าใจ destructuring — เทคนิคที่ใช้ตลอดในงานจริง
ใช้เวลา 2-3 ชั่วโมง
Part 1: Arithmetic Operators — คำนวณเลข
1.1 พื้นฐาน
javascript
5 + 3 // 8 — บวก
5 - 3 // 2 — ลบ
5 * 3 // 15 — คูณ
5 / 3 // 1.6666666666666667 — หาร (ไม่มี integer division แยกต่างหาก — ถ้าหารไม่ลงตัวจะได้ทศนิยม)
5 % 3 // 2 — หารเอาเศษ (modulo)
5 ** 3 // 125 — ยกกำลัง (5³)อันที่มือใหม่ไม่คุ้นคือ % (modulo) — มันคือ "เศษที่เหลือจากการหาร":
javascript
10 % 3 // 1 — 10 หาร 3 ได้ 3 เหลือเศษ 1
10 % 2 // 0 — 10 หาร 2 ลงตัว เหลือ 0% มีประโยชน์มาก — เช่น เช็คเลขคู่/คี่:
javascript
8 % 2 === 0 // true — 8 เป็นเลขคู่ (หาร 2 ลงตัว)
7 % 2 === 0 // false — 7 เป็นเลขคี่1.2 เพิ่ม/ลด ทีละหนึ่ง
javascript
let x = 5;
x++; // เพิ่ม 1 — x กลายเป็น 6
x--; // ลด 1 — x กลายเป็น 5กรณีทั่วไป — เขียน x++ เดี่ยว ๆ (ไม่ assign) ไม่ต้องกังวลอะไร:
javascript
let count = 0;
count++; // count กลายเป็น 1 — ใช้แบบนี้บ่อยที่สุดEdge case (ไม่ค่อยเจอ) — x++ (postfix) ต่างจาก ++x (prefix) เมื่อเอาค่าไป assign:
javascript
let a = 5;
let b = a++; // b ได้ค่า 5 ก่อน แล้ว a ค่อยเพิ่มเป็น 6 (postfix: ใช้ก่อน เพิ่มทีหลัง)
let c = 5;
let d = ++c; // c เพิ่มเป็น 6 ก่อน แล้ว d ได้ค่า 6 (prefix: เพิ่มก่อน ใช้ทีหลัง)→ ถ้าไม่ได้เอาค่า x++ ไป assign ต่อ ก็ไม่ต้องสนใจความต่างนี้
1.3 Math — เครื่องมือคณิตศาสตร์
JavaScript มี object ชื่อ Math ที่รวมฟังก์ชันคณิตศาสตร์:
javascript
Math.round(3.7) // 4 — ปัดเศษ
Math.floor(3.7) // 3 — ปัดลง
Math.ceil(3.2) // 4 — ปัดขึ้น
Math.abs(-5) // 5 — ค่าสัมบูรณ์ (เอาเครื่องหมายลบออก)
Math.max(1, 5, 3) // 5 — ค่ามากสุด
Math.min(1, 5, 3) // 1 — ค่าน้อยสุด
Math.sqrt(16) // 4 — รากที่สอง
Math.pow(2, 10) // 1024 — ยกกำลัง (= 2 ** 10)
Math.random() // เลขสุ่ม 0 ถึง 1 (ไม่ถึง 1)สูตรที่ใช้บ่อย — สุ่มเลขจำนวนเต็ม 0 ถึง 9:
javascript
Math.floor(Math.random() * 10)อธิบาย: Math.random() ได้ 0.xxx → คูณ 10 ได้ 0.x ถึง 9.x → Math.floor ปัดลง → ได้ 0-9
Part 2: Assignment Operators — กำหนดค่า
= คือการกำหนดค่า — แต่มีตัวย่อที่รวม "คำนวณ + กำหนดค่า":
javascript
let x = 10;
x += 5; // เท่ากับ x = x + 5 → x เป็น 15
x -= 3; // เท่ากับ x = x - 3 → x เป็น 12
x *= 2; // เท่ากับ x = x * 2 → x เป็น 24
x /= 4; // เท่ากับ x = x / 4 → x เป็น 6
x %= 4; // เท่ากับ x = x % 4 → x เป็น 2ตัวย่อพวกนี้ทำให้โค้ดสั้นและอ่านง่ายขึ้น — x += 5 อ่านว่า "เพิ่ม x ขึ้น 5"
Part 3: Comparison Operators — เปรียบเทียบ
operator เปรียบเทียบให้ผลเป็น boolean (true/false) — ใช้กับการตัดสินใจ
3.1 เปรียบเทียบมาก/น้อย
ตัวดำเนินการเปรียบเทียบ (>, <, >=, <=) ใช้เทียบค่าสองค่าแล้วคืนผลเป็น boolean (true/false) — เป็นพื้นฐานของการเขียนเงื่อนไข if:
javascript
5 > 3 // true — มากกว่า
5 < 3 // false — น้อยกว่า
5 >= 5 // true — มากกว่าหรือเท่ากับ
5 <= 4 // false — น้อยกว่าหรือเท่ากับ3.2 ⚠️ เปรียบเทียบเท่ากัน — == vs === (เรื่องสำคัญที่สุดของบท)
JavaScript มี 2 วิธีเช็คว่า "เท่ากัน":
=== (เปรียบเทียบแบบเข้มงวด / strict equality — "เข้มงวด" = ชนิดต้องตรงด้วย)
- เช็คว่า "ชนิดเหมือนกัน และ ค่าเหมือนกัน"
- ไม่แปลงชนิดข้อมูล
javascript
5 === 5 // true
5 === "5" // false — ชนิดต่างกัน (number กับ string)
"a" === "a" // true
true === true // true== (เปรียบเทียบแบบหลวม / loose equality — "หลวม" = แปลงชนิดให้ก่อน)
- เช็คแค่ "ค่าเหมือนกัน" — แปลงชนิดให้ก่อนเปรียบเทียบ
javascript
5 == 5 // true
5 == "5" // true — ⚠️ แปลง "5" เป็น 5 ก่อน แล้วถึงเทียบ
true == 1 // true — ⚠️ แปลง true เป็น 1
0 == "" // true — ⚠️ แปลกประหลาด
null == undefined // trueปัญหาของ == คือ — กฎการแปลงชนิดของมันซับซ้อนและคาดเดายาก ทำให้เกิดบั๊กที่หาไม่เจอ:
javascript
0 == false // true
0 == "" // true
"" == false // true
0 == "0" // true
"0" == false // true
null == 0 // false — ⚠️ แต่ null == undefined เป็น true (ไม่สม่ำเสมอ)กฎทอง — สำคัญที่สุดของบทนี้: ใช้
===และ!==เสมอ — ห้ามใช้==และ!=ยกเว้นมีเหตุผลพิเศษจริง ๆ
===คาดเดาได้ — ชนิดต้องตรง ค่าต้องตรง จบ.==คือบ่อเกิดของบั๊ก
javascript
5 !== "5" // true — ไม่เท่ากัน (เพราะชนิดต่าง)
5 != "5" // false — ⚠️ อย่าใช้3.3 NaN — ค่าที่ไม่เท่ากับอะไรเลย แม้แต่ตัวเอง
จำ NaN จากบทที่ 02 ได้ไหม — มันมีพฤติกรรมแปลก:
javascript
NaN === NaN // false! — NaN ไม่เท่ากับอะไรเลย แม้แต่ตัวเองดังนั้นเช็ค NaN ด้วย === ไม่ได้ — ต้องใช้ Number.isNaN():
javascript
Number.isNaN(NaN) // true ← ใช้อันนี้
Number.isNaN(5) // false3.4 เปรียบเทียบ String
string เปรียบเทียบตามลำดับตัวอักษร (เทียบ Unicode codepoint — รหัสตัวอักษร):
javascript
"apple" < "banana" // true — a มาก่อน b
"a" < "b" // true
"Z" < "a" // true — ⚠️ ตัวพิมพ์ใหญ่มีรหัสน้อยกว่าตัวพิมพ์เล็กจำง่าย ๆ: ตัวพิมพ์ใหญ่ A-Z มีรหัส Unicode 65-90 ส่วนตัวพิมพ์เล็ก a-z มีรหัส 97-122 — ตัวพิมพ์ใหญ่ ทุกตัว จึงมาก่อนตัวพิมพ์เล็กเสมอเวลาเทียบ
หมายเหตุ: การเทียบแบบนี้ใช้รหัส Unicode ดิบ — เหมาะกับ ASCII (a-z, A-Z) แต่ ไม่เหมาะกับภาษาไทยหรือภาษาอื่น เพราะลำดับ Unicode ไม่ตรงกับลำดับพจนานุกรม
ถ้าต้องเรียงคำไทยหรือเทียบแบบไม่สนตัวพิมพ์ใหญ่/เล็ก ใช้
String.prototype.localeCompare():javascript"ก".localeCompare("ข") // -1 (ก มาก่อน ข) "Apple".localeCompare("apple", "en", { sensitivity: "base" }) // 0 (ถือว่าเท่ากัน)
Part 4: Logical Operators — ตรรกะ
operator ตรรกะใช้รวมเงื่อนไขหลายอัน
4.1 && (และ), || (หรือ), ! (ไม่)
ตัวดำเนินการตรรกะใช้รวมหรือกลับเงื่อนไข — && (และ: จริงทั้งคู่ถึงจริง), || (หรือ: จริงตัวใดตัวหนึ่งก็จริง), ! (ไม่: กลับค่า):
javascript
true && true // true — && (และ): จริงทั้งคู่ถึงจะจริง
true && false // false
true || false // true — || (หรือ): จริงอย่างน้อยตัวหนึ่งก็จริง
false || false // false
!true // false — ! (ไม่): กลับค่า
!false // trueตัวอย่างใช้จริง:
javascript
let age = 20;
let hasLicense = true;
age >= 18 && hasLicense // true — อายุถึง และ มีใบขับขี่
age < 18 || !hasLicense // false4.2 Short-circuit — && || คืน "ค่า" ไม่ใช่แค่ boolean
นี่เป็นจุดที่ JavaScript ต่างจากภาษาอื่น — && และ || จริง ๆ คืนค่าตัวใดตัวหนึ่ง ไม่ใช่แค่ true/false
|| คืนค่าแรกที่เป็น truthy (ถ้าไม่มีเลย คืนตัวสุดท้าย):
javascript
"Alice" || "default" // "Alice" — ตัวแรก truthy ก็คืนเลย
"" || "default" // "default" — ตัวแรก falsy เลยคืนตัวถัดไป
0 || 100 // 100
// กรณีทุกตัว falsy — คืนตัวสุดท้าย
false || null || 0 // 0 (ตัวสุดท้าย เพราะไม่มีตัวไหน truthy เลย)&& คืนค่าแรกที่เป็น falsy (ถ้าไม่มี คืนตัวสุดท้าย):
javascript
"Alice" && "Bob" // "Bob" — ตัวแรก truthy เลยไปดูตัวถัดไป
"" && "Bob" // "" — ตัวแรก falsy ก็คืนเลยทำไม "short-circuit" (ลัดวงจร)? — เพราะมันหยุดทันทีที่รู้คำตอบ ไม่ดูที่เหลือ
ประโยชน์: ใช้ || ตั้งค่าเริ่มต้น (default value)
javascript
function greet(name) {
name = name || "คนแปลกหน้า"; // สำนวนเก่า — ถ้า name เป็น '' หรือ 0 จะได้ default ด้วย (อาจไม่ตั้งใจ)
return "สวัสดี " + name;
}⚠️ ระวัง:
name || "default"จะใช้ default เมื่อ name เป็น""หรือ0ด้วย — ซึ่งอาจไม่ใช่สิ่งที่ต้องการ ดู??ใน Part 4.3 สำหรับวิธีที่ปลอดภัยกว่า
4.3 Nullish Coalescing (ใช้ค่า default เมื่อค่าเป็น null หรือ undefined) — ??
|| มีปัญหา — มันถือว่า 0, "", false เป็น falsy ทั้งหมด ทำให้ default ผิด:
javascript
let count = 0;
let display = count || 10; // display = 10 — ⚠️ ผิด! 0 เป็นค่าที่ถูกต้องoperator ?? (nullish coalescing — feature ของ ES2020, รองรับกว้างมากแล้วใน Node.js และทุก browser สมัยใหม่) แก้ปัญหานี้ — มันใช้ค่า default เฉพาะเมื่อค่าเป็น null หรือ undefined เท่านั้น:
javascript
let count = 0;
let display = count ?? 10; // display = 0 — ✅ ถูก! 0 ไม่ใช่ null/undefined
let name = null;
let n = name ?? "ไม่มีชื่อ"; // "ไม่มีชื่อ" — null เลยใช้ default
"" ?? "default" // "" — "" ไม่ใช่ null/undefined
0 ?? 100 // 0
null ?? 100 // 100
undefined ?? 100 // 100กฎ: ใช้
??เมื่อต้องการ "default ถ้าไม่มีค่า (null/undefined)" — ใช้||เมื่อต้องการ "default ถ้าค่า falsy"ในงานสมัยใหม่ ส่วนใหญ่ใช้
??เพราะปลอดภัยกว่า
⚠️ ห้ามผสม ?? กับ ||/&& โดยไม่ใส่วงเล็บ:
javascript
a || b ?? c // ❌ SyntaxError ตอน parse (โค้ดไม่รันเลย)
(a || b) ?? c // ✅ ต้องใส่วงเล็บ(ข้อนี้บังคับโดย JavaScript ตั้งแต่ตอน parse (ขั้นตอนที่ engine อ่านและตรวจโค้ดก่อนรันจริง) — ไม่ใช่ error ตอนรัน เพราะ JS อยากให้ผู้เขียนชัดเจนว่าตั้งใจให้ลำดับเป็นแบบไหน)
4.4 Logical Assignment — ||=, &&=, ??=
operator สมัยใหม่ (ES2021) ที่รวม "ตรรกะ + กำหนดค่า":
javascript
let x = null;
x ??= 10; // ถ้า x เป็น null/undefined → ใส่ 10 — x กลายเป็น 10
let config = {};
// config.theme เป็น undefined (ยังไม่มี key นี้) → ตั้งเป็น "light"
config.theme ??= "light"; // config.theme = "light"
// ✅ ES2021: ||=, &&=, ??=Part 5: Ternary Operator — if แบบสั้น
? : (ternary) คือ "if-else แบบบรรทัดเดียว":
javascript
condition ? ค่าถ้าจริง : ค่าถ้าเท็จตัวอย่าง:
javascript
let age = 20;
let status = age >= 18 ? "ผู้ใหญ่" : "เด็ก";
console.log(status); // "ผู้ใหญ่"เทียบกับ if ปกติ (สองตัวอย่างนี้แสดงสองสไตล์แยกกัน — อย่ารันพร้อมกันในบล็อกเดียว):
javascript
// แบบที่ 1: if ปกติ — ยาวกว่า
let status;
if (age >= 18) {
status = "ผู้ใหญ่";
} else {
status = "เด็ก";
}javascript
// แบบที่ 2: ternary — บรรทัดเดียว (เลือกใช้แบบใดแบบหนึ่ง)
let status = age >= 18 ? "ผู้ใหญ่" : "เด็ก";ใช้ ternary เมื่อ "เลือกค่าจาก 2 ตัวเลือกง่าย ๆ" — อย่าใช้กับ logic ซับซ้อน (อ่านยาก)
Part 6: Spread กับ Rest — ... (3 จุด)
... คือ operator ที่ทรงพลังมาก ใช้ได้ 2 แบบ — ดูจาก "บริบท"
6.1 Spread — "แผ่ออก"
Spread เอา array/object มา "แผ่" ออกเป็นชิ้น ๆ
กับ Array:
javascript
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5] — แผ่ arr1 ออก แล้วเติม 4, 5
const copy = [...arr1]; // [1, 2, 3] — copy array
// รวม array
const a = [1, 2];
const b = [3, 4];
const merged = [...a, ...b]; // [1, 2, 3, 4]กับ Object:
javascript
const user = { name: "Alice", age: 25 };
const copy = { ...user }; // copy object
const updated = { ...user, age: 26 }; // copy + เปลี่ยน age
const merged = { ...defaults, ...userSettings }; // รวม object (ตัวหลังทับตัวหน้า)(จำได้ไหม — บทที่ 02 เราใช้ { ...obj } copy object — นั่นคือ spread)
ส่งเป็น argument ของ function:
javascript
const numbers = [5, 1, 8, 3];
Math.max(...numbers); // 8 — แผ่ array ออกเป็น Math.max(5, 1, 8, 3)6.2 Rest — "รวบเข้า"
Rest ทำตรงข้าม — "รวบ" หลายค่ามาเป็น array เดียว
ใน parameter ของ function:
javascript
function sum(...numbers) { // รวบทุก argument เป็น array ชื่อ numbers
let total = 0;
for (const n of numbers) total += n; // for...of = วนแต่ละค่าใน array — จะเรียนละเอียดบทที่ 04
return total;
}
sum(1, 2, 3); // 6
sum(1, 2, 3, 4, 5); // 15 — รับกี่ตัวก็ได้💡 ถ้า
for...ofยังดูแปลก — ตอนนี้รู้แค่ว่า "มันวนทุกค่าใน array" ก็พอ บทที่ 04 จะอธิบายครบ
จะ spread หรือ rest — ดูจากบริบท:
...ตอน เรียกใช้/สร้าง = spread (แผ่ออก)...ตอน รับค่า/parameter = rest (รวบเข้า)
Part 7: Destructuring — ดึง property ออกจาก object/array เป็นตัวแปรในบรรทัดเดียว
ปัญหาก่อนมี destructuring: ถ้าต้องดึงค่าหลายตัวจาก object เดียวกัน ต้องเขียนซ้ำ ๆ:
javascript
const name = user.name;
const age = user.age;
const city = user.city; // ยาวมากถ้ามีหลาย fieldDestructuring (การแกะค่า — แยกค่าจาก array/object ออกเป็นตัวแปรย่อยทีละตัว) แก้ปัญหานี้ — ดึงหลายค่าพร้อมกันในบรรทัดเดียว ทำให้โค้ดสั้นและอ่านง่าย
7.1 Destructure Array
การแกะ array คือดึงค่าตามตำแหน่งออกมาเป็นตัวแปรในบรรทัดเดียว (const [a, b] = arr) แทนการเขียน arr[0], arr[1] ทีละตัว — สั้นและอ่านง่ายกว่า:
javascript
const colors = ["แดง", "เขียว", "น้ำเงิน"];
// แบบเก่า — ดึงทีละตัว
const c0 = colors[0]; // "แดง"
const c1 = colors[1]; // "เขียว"javascript
const colors = ["แดง", "เขียว", "น้ำเงิน"];
// destructuring — แกะออกมาทีเดียว (สั้นกว่ามาก)
const [first, second, third] = colors;
console.log(first); // "แดง"
console.log(second); // "เขียว"ลูกเล่น:
javascript
// ข้ามตัวที่ไม่เอา
const [, , third] = colors; // third = "น้ำเงิน"
// ค่า default
const [a, b, c, d = "ดำ"] = colors; // d = "ดำ" (ไม่มีตัวที่ 4)
// rest — รวบที่เหลือ
const [head, ...tail] = [1, 2, 3, 4]; // head = 1, tail = [2, 3, 4]
// สลับค่าตัวแปร (เทคนิคเด็ด)
let x = 1, y = 2;
[x, y] = [y, x]; // x = 2, y = 1💡 ฝึกก่อนไปต่อ: ลองรัน
const [a, b] = [10, 20]; console.log(a, b);ใน Console — ถ้าได้10 20แปลว่าเข้าใจ array destructuring แล้ว
7.2 Destructure Object
javascript
const user = { name: "Alice", age: 25, city: "Bangkok" };
// แบบเก่า
const n = user.name; // "Alice"
const a = user.age; // 25javascript
const user = { name: "Alice", age: 25, city: "Bangkok" };
// destructuring — แกะตามชื่อ key (สั้นกว่ามาก)
const { name, age } = user;
console.log(name); // "Alice"
console.log(age); // 25⚠️ ตอน destructure object — ชื่อตัวแปรต้องตรงกับ key
ลูกเล่น:
javascript
// เปลี่ยนชื่อตัวแปร
const { name: userName } = user; // userName = "Alice"
// ค่า default
const { name, country = "Thailand" } = user; // country = "Thailand" (ไม่มีใน object)
// rest
const { name, ...rest } = user; // name = "Alice", rest = { age: 25, city: "Bangkok" }
// destructure object ซ้อน (ขั้นสูง — ถ้างงข้ามไปก่อนได้)
const data = { user: { profile: { email: "a@x.com" } } };
const { user: { profile: { email } } } = data;
console.log(email); // "a@x.com"7.3 Destructuring ใน Parameter ของ Function
ใช้บ่อยมาก — แกะค่าจาก object ที่ส่งเข้ามาเลย (เรื่อง function เรียนละเอียดบทที่ 05 — ตอนนี้รู้แค่ว่ามันคือ "ก้อนโค้ดที่เรียกใช้ซ้ำได้"):
javascript
// แบบเก่า
function greet(user) {
return `สวัสดี ${user.name} อายุ ${user.age}`;
}
// destructure ใน parameter
function greet({ name, age }) {
return `สวัสดี ${name} อายุ ${age}`;
}
greet({ name: "Alice", age: 25 });→ destructuring คุณจะเห็นทุกที่ในโค้ด React, Node.js — ฝึกให้คล่อง
Part 8: Optional Chaining — ?.
ปัญหา: ถ้าเข้าถึง property ของ object ที่เป็น null/undefined → Error
javascript
const user = null;
user.name; // ❌ TypeError: Cannot read properties of null (อ่าน property ของ null ไม่ได้)operator ?. (optional chaining — เข้าถึง property แบบมีเงื่อนไข: ถ้าตัวก่อนหน้าเป็น null/undefined จะไม่ error; feature ของ ES2020, รองรับกว้างมากแล้วใน Node.js และทุก browser สมัยใหม่) แก้ปัญหานี้ — มันคืน undefined แทนที่จะ Error:
javascript
const user = null;
user?.name; // undefined — ไม่ Error
user?.address?.city; // undefined — เช็คได้หลายชั้นใช้กับ method และ array ได้ด้วย:
javascript
user?.greet?.(); // เรียก method ถ้ามี
user?.items?.[0]; // เข้าถึง array ถ้ามีเปรียบเทียบกับวิธีเก่า:
javascript
// แบบเก่า — ยาว
const city = user && user.address && user.address.city;
// optional chaining — สั้น
const city = user?.address?.city;?. มักใช้คู่กับ ??:
javascript
const city = user?.address?.city ?? "ไม่ระบุ";→ "เอา city ถ้ามี ไม่งั้นใช้ 'ไม่ระบุ'" — ปลอดภัย ไม่มีทาง Error
Part 9: typeof, instanceof, in
operator พิเศษสำหรับเช็คชนิดและความเป็นเจ้าของ
9.1 typeof — เช็คชนิด
typeof ใช้ตรวจว่าค่าหนึ่งเป็นชนิดอะไร (คืนเป็น string เช่น "number") — มีประโยชน์เวลาเช็คก่อนทำงาน แต่ระวังกับดักในตำนาน typeof null ได้ "object":
javascript
typeof 42 // "number"
typeof "hi" // "string"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" ← บั๊กในตำนาน
typeof {} // "object"
typeof [] // "object"
typeof function(){} // "function"
// ใช้เช็คก่อนทำงาน
if (typeof callback === "function") {
callback();
}9.2 in — เช็คว่ามี key ไหม
in ใช้ตรวจว่า object มี key ที่ระบุหรือไม่ (คืน true/false) — ต่างจากการเช็คค่า เพราะ key ที่มีค่าเป็น undefined ก็ยังนับว่า "มี":
javascript
const user = { name: "Alice", age: 25 };
"name" in user // true
"email" in user // false9.3 instanceof — เช็คว่าเป็น instance (ตัวอย่าง/วัตถุที่สร้างจาก class) ของ class ไหม
(เรื่อง class เรียนละเอียดบทที่ 06 — ตอนนี้รู้แค่ว่าเป็น "พิมพ์เขียวสำหรับสร้าง object")
javascript
[] instanceof Array // true
new Date() instanceof Date // true⚠️ กับดัก instanceof — ใช้ข้าม realm ไม่ได้: ถ้า array ถูกสร้างมาจาก iframe คนละอัน, worker, หรือ Node vm module — instanceof Array จะคืน false แม้มันเป็น array จริง ๆ เพราะคนละ Array constructor
เช็ค array ที่แน่นอนกว่า typeof และ instanceof (ใช้ได้ข้าม realm):
javascript
Array.isArray([]) // true ← ใช้อันนี้เช็ค array (ปลอดภัยกว่า instanceof)
Array.isArray("abc") // falsePart 10: Operator Precedence — ลำดับการคำนวณ
operator มี "ลำดับความสำคัญ" — เหมือนคณิตศาสตร์ (คูณหารก่อนบวกลบ):
javascript
2 + 3 * 4 // 14 — คูณก่อน (3*4=12) แล้วบวก (2+12)
(2 + 3) * 4 // 20 — วงเล็บก่อนลำดับคร่าว ๆ (สูง → ต่ำ) — ตารางนี้ตัด bitwise operator ออกเพราะใช้น้อยในงานทั่วไป แต่ใส่ typeof/in/instanceof ไว้เพราะบทนี้สอนไปแล้ว:
()วงเล็บ**ยกกำลังtypeof,!, unary-/+(เช่น-5,!true) — ตัวดำเนินการที่ใช้กับค่าเดียว*/%+-<><=>=,in,instanceof===!==&&||??(มี precedence เดียวกัน แต่ห้ามผสมกันโดยไม่ใส่วงเล็บ — SyntaxError)? :ternary=+=-=*=ฯลฯ กำหนดค่า,(comma operator — ใช้น้อยมาก, คืนค่าตัวขวาสุด)
ตารางเต็ม (รวม bitwise operator เช่น
&,|,^) ดูได้ที่ MDN operator precedence
กฎทอง: ถ้าไม่แน่ใจลำดับ — ใส่วงเล็บ มันทำให้โค้ดชัดเจน อ่านง่าย ไม่ต้องจำลำดับ
javascript
// อ่านยาก
let result = a && b || c && d;
// ชัดเจน
let result = (a && b) || (c && d);Part 11: Lab — ลงมือทำ
Lab 1: ทายผลลัพธ์
ลองทายผลก่อนรันแต่ละบรรทัด แล้วพิมพ์ลง Console เช็ค — โจทย์เน้นจุดที่สับสนบ่อย: == vs ===, NaN, และ || vs ??:
javascript
5 === "5"
5 == "5"
0 == false
0 === false
null == undefined
null === undefined
NaN === NaN
"" || "default"
"" ?? "default"
0 || 100
0 ?? 100Lab 2: เครื่องคิดเลขส่วนลดด้วย ternary
ฝึกใช้ ternary operator (เงื่อนไข ? ค่าจริง : ค่าเท็จ) กับโจทย์คำนวณส่วนลดตามสถานะสมาชิก:
javascript
const price = 1000;
const isMember = true;
const discountRate = isMember ? 0.2 : 0.05;
const finalPrice = price * (1 - discountRate);
console.log(`ส่วนลด: ${discountRate * 100}%`);
console.log(`ราคาสุทธิ: ${finalPrice} บาท`);Lab 3: Destructuring + default
ฝึกแกะ object ในพารามิเตอร์ฟังก์ชันพร้อมกำหนดค่า default — แพตเทิร์นที่ใช้บ่อยมากเวลารับ options:
javascript
function createUser({ name, role = "user", active = true } = {}) {
return { name, role, active };
}
console.log(createUser({ name: "Alice" }));
console.log(createUser({ name: "Bob", role: "admin" }));
console.log(createUser());อธิบายส่วนยุ่ง ๆ:
role = "user",active = true— ค่า default ถ้าไม่ส่งมาใน object= {}ด้านนอกสุด — ค่า default ถ้าไม่ส่ง argument เลย (เช่นเรียกcreateUser()ตัวเปล่า) → ถ้าไม่มี= {}จะ error เพราะ JavaScript จะพยายาม destructure จากundefined
Lab 4: Optional chaining
javascript
const response = {
data: {
user: { name: "Alice" }
}
};
console.log(response?.data?.user?.name); // "Alice"
console.log(response?.data?.order?.id); // undefined
console.log(response?.data?.order?.id ?? "ไม่มี order"); // "ไม่มี order"Part 12: Checkpoint
%(modulo) ทำอะไร? ใช้เช็คเลขคู่ยังไง?x += 5เท่ากับอะไร?===ต่าง==ยังไง? ควรใช้อันไหน? ทำไม?- ทำไม
NaN === NaNได้false? เช็ค NaN ยังไง? &&กับ||คืน "ค่า" ไม่ใช่แค่ boolean — อธิบาย??ต่าง||ยังไง? ใช้อันไหนเมื่อไหร่?- Spread กับ Rest ต่างกันยังไง? ดูจากอะไร?
- Destructuring คืออะไร? ยกตัวอย่าง
?.(optional chaining) แก้ปัญหาอะไร?- ถ้าไม่แน่ใจลำดับ operator ควรทำยังไง?
Part 13: สรุปบทนี้
- Arithmetic:
+ - * / % **—%คือเศษจากการหาร ===เสมอ ไม่ใช่==— เรื่องสำคัญที่สุด==แปลงชนิดทำให้เกิดบั๊กNaNเช็คด้วยNumber.isNaN()(เพราะNaN === NaNเป็น false)&&||คืน "ค่า" จริง ๆ ไม่ใช่แค่ boolean (short-circuit)??= default ถ้า null/undefined /||= default ถ้า falsy → ใช้??เป็นหลัก...= spread (แผ่ออก) หรือ rest (รวบเข้า) — ดูจากบริบท- Destructuring = แกะค่าจาก array/object — ใช้บ่อยมากในงานจริง
?.= เข้าถึง property อย่างปลอดภัย ไม่ Error ถ้าเป็น null/undefined- ไม่แน่ใจลำดับ operator → ใส่วงเล็บ
บทต่อไป — Control Flow: ควบคุมการทำงานด้วย if และ loop