Type Coercion là việc JavaScript **tự động chuyển đổi kiểu dữ liệu** khi thực hiện phép toán giữa các kiểu khác nhau. Khác với Type Casting (ép kiểu tường minh do dev chủ động).
Quy tắc chính:
+ với string → **concatenation** (nối chuỗi), ép kiểu toán hạng còn lại thành string
-, *, /, % → **ép kiểu thành Number**
== (loose equality) → ép kiểu cả hai về cùng kiểu rồi so sánh
=== (strict equality) → **KHÔNG** ép kiểu
Ví dụ minh họa
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Type Coercion JS</title>
<style>
body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; padding: 20px; }
.sample { font-size: 20px; font-weight: 500; margin: 10px 0; color: red; }
.result { font-size: 18px; font-weight: 500; margin: 10px 0; color: green; }
button { padding: 8px 16px; cursor: pointer; }
table { border-collapse: collapse; width: 100%; margin-top: 20px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: center; }
th { background: #f5f5f5; }
</style>
</head>
<body>
<h1>JavaScript Type Coercion (Ép kiểu ngầm)</h1>
<div class="sample" id="sample">22</div>
<div class="result" id="result"></div>
<button class="Btn" id="btn">NHẤN VÀO ĐÂY</button>
<h3> Nhấn nút để cộng số 22 (string) với 5 (number) </h3>
<script>
const sampleEle = document.querySelector('#sample');
const resEle = document.querySelector("#result");
document.querySelector("#btn").addEventListener("click", () => {
const str = sampleEle.innerHTML; // "22"
const num = 5;
// Type Coercion: String + Number -> String
const result = str + num; // "22" + 5 -> "225"
resEle.innerHTML = `
Expression: "22" + 5
Kết quả: "${result}" (${typeof result})
Giải thích: Toán tử + với string → concatenation, ép 5 thành "5"
`;
// Bảng so sánh coercion
let tableHtml = 'Bảng Type Coercion phổ biến:
| Biểu thức | Kết quả | Loại coercion |
';
const cases = [
['"22" + 5', '"22" + 5', 'String + Number → String'],
['"22" - 5', '"22" - 5', 'String - Number → Number'],
['"22" * 5', '"22" * 5', 'String * Number → Number'],
['"22" / 5', '"22" / 5', 'String / Number → Number'],
['true + 1', 'true + 1', 'Boolean + Number → Number'],
['false + 1', 'false + 1', 'Boolean + Number → Number'],
['null + 1', 'null + 1', 'Null + Number → Number'],
['undefined + 1', 'undefined + 1', 'Undefined + Number → NaN'],
['[] + 1', '[] + 1', 'Array + Number → String'],
['[1] + 2', '[1] + 2', 'Array + Number → String'],
['{} + 1', '{} + 1', 'Object + Number → String (hoặc syntax error)'],
['"hello" + []', '"hello" + []', 'String + Array → String'],
];
cases.forEach(([expr, desc, type]) => {
try {
// eslint-disable-next-line no-eval
const result = eval(expr);
tableHtml += `${expr} | ${JSON.stringify(result)} | ${type} |
`;
} catch (e) {
tableHtml += `${expr} | Error: ${e.message} |
`;
}
});
tableHtml += '
';
resEle.innerHTML += tableHtml;
});
</script>
</body>
</html>
Kết quả
Expression: "22" + 5
Kết quả: "225" (string)
Giải thích: Toán tử + với string → concatenation, ép 5 thành "5"
Bảng Type Coercion chi tiết:
| Biểu thức | Kết quả | Giải thích |
"22" + 5 | "225" | String + Number → String concat |
"22" - 5 | 17 | String - Number → Number |
"22" * "2" | 44 | String * String → Number |
true + 1 | 2 | Boolean → Number (true=1) |
false + 1 | 1 | Boolean → Number (false=0) |
null + 1 | 1 | Null → Number (0) |
undefined + 1 | NaN | Undefined → Number (NaN) |
[] + 1 | "1" | Array → "" (empty string) + "1" |
[1,2] + 3 | "1,23" | Array → "1,2" + "3" |
{} + 1 | 1 hoặc "[object Object]1" | Context dependent (block vs expression) |
== vs === (Loose vs Strict Equality):
// Loose equality (==) - CÓ coercion
1 == "1" // true
true == 1 // true
false == 0 // true
null == undefined // true
"" == 0 // true
[] == 0 // true
[] == "" // true
// Strict equality (===) - KHÔNG coercion
1 === "1" // false
true === 1 // false
null === undefined // false
Best Practice:
- Luôn dùng === và !== (trừ khi có lý do cụ thể dùng ==)
- Ép kiểu tường minh trước khi so sánh:
Number(input) === 5
- ESLint rule:
eqeqeq: ["error", "always"]
- Hiểu coercion để debug, không để nó "lén lút" trong code