Lão Tử nói: “Đạo mà diễn tả được thì đó không còn là đạo bất biến nữa, tên mà gọi ra được thì đó không còn là tên bất biến nữa.”
Sự trống vắng bất ổn#
null và undefined là hai giá trị đặc biệt trong Javascript để ám chỉ sự trống vắng.
Nhiều lập trình viên, vừa yêu thích giấy vệ sinh, vừa dùng lẫn lộn cả hai giá trị này trong code, thậm chí có người còn coi chúng chỉ là hai tên gọi khác cho cùng một khái niệm “rỗng”. Với niềm tin như vậy họ có thể viết code như này:
if (randomValue) {
// do something
}
Rẽ nhánh như vậy sẽ bất ổn bởi ép kiểu ngầm sẽ đưa cả số 0
và ""
về false
. Nếu ta sửa lại:
if (randomValue == null) {
// do something
}
thì sẽ vi phạm luật so sánh tuyệt đối (dùng ===
) của công cụ lint code như ESLint. Cách viết này cũng không rõ ràng khi thoạt nhìn code có vẻ chỉ kiểm tra null
mà lại kiểm tra luôn cả undefined
. Nếu muốn rõ ràng mà viết như sau:
if (randomValue === undefined || randomValue === null) {
// do something
}
thì code lại cồng kềnh.
So sánh#
Lợi thế của undefined
#
- Tham số mặc định của hàm chỉ hỗ trợ
undefined
. - Giá trị mặc định khi destructuring chỉ hỗ trợ
undefined
. typeof undefined
là"undefined"
, không gây bối rối nhưtypeof null
là"object"
.- Thực hiện phép tính toán với giá trị không xác định cho kết quả như dự đoán:
2 + undefined; // NaN
2 + null; // 2
Lợi thế của null
#
- JSON chỉ hỗ trợ
null
. - Component của React chỉ hỗ trợ trả về
null
khi không render gì (undefined
không hỗ trợ). - DOM APIs, như
document.querySelector()
, thường hỗ trợnull
. - Hàm có thể phân biệt được giữa
return
vàreturn null
, khó phân biệt được giữareturn
vàreturn undefined
. - Dễ phân biệt được trường nào không tồn tại trong object:
obj.prop === undefined
-> không tồn tạiobj.prop === null
-> tồn tại, chưa có giá trị
null
được các database hỗ trợ tốt hơn:- SQL có giá trị
NULL
để ánh xạ vớinull
trong JS. - Prisma coi
null
là một giá trị, cònundefined
được hiểu là không làm gì! Nghĩa là các trường có kiểu.undefined
sẽ bị bỏ qua khi INSERT hay UPDATE.
- SQL có giá trị
Quan điểm#
Code dùng null
sẽ tường minh và dễ kiểm soát hơn, bởi khi bạn set một biến là null
, bạn biết chắc chắn tồn tại một biến như vậy, chỉ là chưa có giá trị mà thôi.
Tuy nhiên, do tham số mặc định chỉ hỗ trợ undefined
, một lập trình viên React có thể phải viết code như sau để prop có thể nhận giá trị mặc định nếu null
:
<SomeComponent
a={model.a === null ? undefined : model.a}
b={model.b === null ? undefined : model.b}
c={model.c === null ? undefined : model.c}
/>
Thực sự xấu xí!
Coding guideline của Typescript yêu cầu chỉ dùng undefined
.
Khai báo kiểu dùng undefined
cũng thân thiện với người dùng Typescript:
interface PostEntity {
category?: string; // có thể là `string` hoặc `undefined`
}
// If you use `null`
interface PostEntity {
category: string | null; // dài dòng hơn
}
Cộng đồng ESLint cũng khuyến nghị hạn chế sử dụng null
.
// Fail
let foo = null;
if (bar == null) {}
// Pass
let foo;
const foo = Object.create(null);
if (foo === null) {}
Với những trường hợp bắt buộc phải sử dụng null
, ta có thể đơn giản là disable ESLint rule cho dòng khai báo đó. Để code không bị disable rải rác nhiều nơi, ta có thể lách luật như sau:
// eslint-disable-next-line no-null/no-null
const NULL = null;
export default NULL;
JSON tự động loại bỏ các trường undefined
khi stringify
. Do JSON chỉ hỗ trợ null
, bạn cần một replacer để thay thế undefined
thành null
:
const user = { name: 'Duy Trung', address: undefined };
const replacer = (key, value) =>
typeof value === 'undefined' ? null : value;
JSON.stringify(user, replacer); // -> "{\"name\":\"Duy Trung\",\"address\":null}"
Kết luận#
- Vì lý do lịch sử mà trong Javascript tồn tại hai giá trị đều ám chỉ sự “rỗng” là
null
vàundefined
. Dù khá giống nhau nhưng hai giá trị này vẫn có những đặc điểm riêng biệt. - Việc sử dụng lẫn lộn cả
null
vàundefined
trong code mà không có một lý lẽ rõ ràng có thể dẫn đến bug và tạo gánh nặng khi maintain. - Cộng đồng Typescript và ESLint có xu hướng hạn chế sử dụng
null
, ưu tiênundefined
, với những lý do chi tiết cho thấyundefined
mang lại ít phiền phức hơn so vớinull
. Brendan Eich - cha đẻ của Javascript - cũng đồng ý như vậy: