JavaScript luôn truyền tham số bằng giá trị (pass by value). Tuy nhiên, hành vi khác nhau giữa kiểu nguyên thủy (primitive) và kiểu tham chiếu (object/array).
1. Pass by Value (Kiểu nguyên thủy)
Với string, number, boolean, null, undefined, symbol, bigint: giá trị được sao chép. Thay đổi bên trong hàm không ảnh hưởng biến ngoài.
Ví dụ
<script>
let a = 1;
function thayDoi(val) {
val = 2; // Chỉ thay đổi bản sao cục bộ
}
thayDoi(a);
document.write(a); // 1 — không đổi
</script>
2. "Pass by Reference" giả vờ (Object/Array)
Với object/array: giá trị truyền đi là tham chiếu (địa chỉ bộ nhớ) — nhưng bản thân tham chiếu được truyền bằng giá trị. Do đó:
- Mutation (đổi nội dung): Ảnh hưởng object gốc.
- Reassignment (gán lại): Không ảnh hưởng object gốc.
Ví dụ Mutation — Ảnh hưởng gốc
<script>
let obj = { num: 1 };
function mut(val) {
val.num = 2; // Thay đổi property của object gốc
}
mut(obj);
document.write(JSON.stringify(obj)); // {"num":2}
</script>
Ví dụ Reassignment — KHÔNG ảnh hưởng gốc
<script>
let obj = { num: 1 };
function reassign(val) {
val = { num: 2 }; // Tạo object mới, gán cho biến cục bộ val
}
reassign(obj);
document.write(JSON.stringify(obj)); // {"num":1} — không đổi
</script>
Tóm tắt trực quan
| Hành động | Primitive | Object/Array |
|---|---|---|
Gán lại tham số (param = ...) | Không ảnh hưởng gốc | Không ảnh hưởng gốc |
Thay đổi property/element (prop = ...) | Không áp dụng | Ảnh hưởng gốc |
Mẹo: Tạo bản sao thật sự (Deep Clone)
// Shallow clone
const copy1 = { ...original };
const copy2 = Object.assign({}, original);
// Deep clone (hạn chế: không hỗ trợ function, Date, RegExp, circular ref)
const deep = JSON.parse(JSON.stringify(original));