Symbol.toPrimitive คืออะไร?
Date.prototype[Symbol.toPrimitive] เป็นเมธอดพิเศษ (Well-known Symbol) ที่ JavaScript เรียกใช้เมื่อต้องการแปลง Date object ให้เป็น Primitive Value (string, number, หรือ default)
- ถูกเรียกอัตโนมัติเมื่อมีการ Type Coercion
- รับ parameter
hint3 ค่า:"string","number","default" Dateobject ignore hint และทำงานเหมือนhint === "string"เสมอ (สำหรับ backward compatibility)
ตัวอย่างโค้ดครบถ้วน
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Date @@toPrimitive</title>
<style>
body { font-family: 'Segoe UI', sans-serif; padding: 20px; max-width: 700px; margin: 0 auto; }
.panel { background: #f5f5f5; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
.code { background: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 4px; font-family: monospace; overflow-x: auto; }
.output { background: #e8f5e9; padding: 15px; border-radius: 4px; font-family: monospace; white-space: pre-wrap; }
button { padding: 10px 20px; background: #7e32d4; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 10px; }
button:hover { background: #6a1b9a; }
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
th, td { padding: 10px; border: 1px solid #ddd; text-align: left; }
th { background: #7e32d4; color: white; }
</style>
</head>
<body>
<h1>Date.prototype[Symbol.toPrimitive]()</h1>
<p>สาธิตการแปลง Date object เป็น Primitive values ด้วย hint ต่างๆ</p>
<div class="panel">
<button onclick="demoToPrimitive()">ทดสอบ Symbol.toPrimitive</button>
<button onclick="demoCoercion()">ทดสอบ Type Coercion อัตโนมัติ</button>
<button onclick="demoCustom()">ทดสtoverride Symbol.toPrimitive</button>
</div>
<div class="panel">
<h3>ผลลัพธ์ Symbol.toPrimitive</h3>
<div class="output" id="output1"></div>
</div>
<div class="panel">
<h3>Type Coercion ต่างๆ</h3>
<div class="output" id="output2"></div>
</div>
<script>
const output1 = document.getElementById('output1');
const output2 = document.getElementById('output2');
const date = new Date('2024-01-15T10:30:45.123Z');
function log(el, msg) {
el.textContent += msg + '\n';
}
function demoToPrimitive() {
output1.textContent = '';
const sym = Symbol.toPrimitive;
log(output1, `Date object: ${date}`);
log(output1, `typeof date: ${typeof date}`);
log(output1, `---`);
// เรียกโดยตรงด้วย hint ต่างๆ
const asString = date[sym]('string');
const asNumber = date[sym]('number');
const asDefault = date[sym]('default');
log(output1, `date[Symbol.toPrimitive]('string') = "${asString}" (type: ${typeof asString})`);
log(output1, `date[Symbol.toPrimitive]('number') = ${asNumber} (type: ${typeof asNumber})`);
log(output1, `date[Symbol.toPrimitive]('default') = "${asDefault}" (type: ${typeof asDefault})`);
log(output1, `---`);
log(output1, 'หมายเหตุ: Date ไม่สนใจ hint - คืนค่า string เสมอ (เหมือน toString)');
}
function demoCoercion() {
output2.textContent = '';
// String context
log(output2, `String(date) = "${String(date)}"`);
log(output2, `date.toString() = "${date.toString()}"`);
log(output2, `date.toISOString() = "${date.toISOString()}"`);
log(output2, `date.toLocaleString() = "${date.toLocaleString('th-TH')}"`);
log(output2, `'' + date = "${'' + date}"`);
log(output2, `\`Date: \${date}\` = \`Date: ${date}\``);
log(output2, `---`);
// Number context
log(output2, `Number(date) = ${Number(date)}`);
log(output2, `+date = ${+date}`);
log(output2, `date.valueOf() = ${date.valueOf()}`);
log(output2, `date.getTime() = ${date.getTime()}`);
log(output2, `---`);
// Default context (==, +, etc.)
log(output2, `date == "${date}" → ${date == date.toString()}`);
log(output2, `date + 1000 = ${date + 1000} (string concat)`);
log(output2, `date - 0 = ${date - 0} (number - date = timestamp)`);
}
function demoCustom() {
output1.textContent += '\n--- Custom Override ---\n';
// สร้าง object ที่มี Symbol.toPrimitive กำหนดเอง
const customObj = {
value: 42,
[Symbol.toPrimitive](hint) {
log(output1, ` [Custom] hint = "${hint}"`);
if (hint === 'number') return this.value;
if (hint === 'string') return `[Custom: ${this.value}]`;
return this.value; // default
}
};
log(output1, `Number(customObj) = ${Number(customObj)}`);
log(output1, `String(customObj) = "${String(customObj)}"`);
log(output1, `customObj + 10 = ${customObj + 10}`);
log(output1, `\`Value: \${customObj}\` = \`Value: ${customObj}\``);
}
demoToPrimitive();
</script>
</body>
</html>
พฤติกรรมของ Date กับ Hint ต่างๆ
| Hint | การเรียกใช้ | ผลลัพธ์ | Type |
|---|---|---|---|
| string | String(date), date.toString(), \`\${date}\` | "Mon Jan 15 2024 17:30:45 GMT+0700" | string |
| number | Number(date), +date, date.valueOf() | 1705312245123 (timestamp ms) | number |
| default | date == "something", date + 1000 | "Mon Jan 15 2024 17:30:45 GMT+0700" | string |
ข้อสังเกตสำคัญ: Date ไม่เคารพ Hint "number" ใน toPrimitive
// Date object behavior (special case for backward compatibility)
date[Symbol.toPrimitive]('number') // คืนค่า STRING ไม่ใช่ number!
// ต้องใช้ date.valueOf() หรือ +date หรือ Number(date) แทน
เหตุผล: เพื่อความเข้ากันได้กับโค้ดเก่า ที่คาดหวังว่า date + "" และ date == "string" จะทำงานแบบ string comparison
การ Override Symbol.toPrimitive ใน Object ตัวเอง
const temperature = {
celsius: 25,
[Symbol.toPrimitive](hint) {
switch (hint) {
case 'number': return this.celsius;
case 'string': return `${this.celsius}°C`;
default: return this.celsius; // default มักใช้ number
}
}
};
console.log(Number(temperature)); // 25
console.log(String(temperature)); // "25°C"
console.log(temperature + 10); // 35 (default → number)
console.log(`Temp: ${temperature}`); // "Temp: 25°C" (string context)
Related Methods
date.toString()- Human readable string (local time)date.toISOString()- ISO 8601 format (UTC)date.toLocaleString()- Locale-aware formattingdate.valueOf()/date.getTime()- Timestamp (milliseconds since epoch)+date/Number(date)- แปลงเป็น number (timestamp)
Browser Support
Symbol.toPrimitive: Chrome 47+, Firefox 44+, Safari 10+, Edge 15+- รองรับในทุกเบราว์เซอร์สมัยใหม่ (ES2015+)