Null vs undefined là cặp giá trị dễ gây nhầm lẫn với những ai mới bắt đầu học JavaScript. Cả hai đều đại diện cho “không có giá trị”, nhưng chúng lại khác nhau về mục đích sử dụng, nguồn gốc và cách JavaScript xử lý chúng trong các phép toán logic và so sánh.
Đọc bài viết sau để được giải đáp chi tiết hơn về:
- Tổng quan về 2 giá trị null và undefined trong JavaScript: định nghĩa, cú pháp và cách sử dụng.
- Một số kiểu (type) của null và undefined.
- So sánh chi tiết giữa null với undefined.
- Khi nào nên sử dụng null hoặc khi nào nên sử dụng undefined.
- Một số câu hỏi thường gặp liên quan về null với undefined.
Giá trị null trong JavaScript
Từ khóa null biểu thị một giá trị vắng mặt được xác định một cách có chủ ý.
Cú pháp:
typeof null
> "object"
null là một kiểu dữ liệu nguyên thủy (primitive), mặc dù toán tử typeof lại trả về kết quả là object. Đây là một lỗi tồn tại từ phiên bản đầu tiên của JavaScript và được giữ nguyên cho đến nay nhằm tránh làm gián đoạn hành vi mong đợi của các chương trình trên web. Bạn nên lưu ý rằng null khác hoàn toàn với đối tượng (object) ở chỗ là nó không sở hữu bất kỳ thuộc tính hoặc phương thức nào, và không thể mở rộng thêm tính năng.
Bạn có thể khai báo một biến với giá trị null khi muốn biểu thị rằng biến đó sẽ được gán giá trị sau trong chương trình, hoặc để chỉ rõ rằng giá trị đang bị thiếu một cách có chủ đích. Bạn cũng có thể gán null cho một tham chiếu (reference) hiện có để xóa bỏ giá trị trước đó.
Giá trị undefined trong JavaScript
undefined là một giá trị nguyên thủy (primitive) được gán cho các biến vừa được khai báo nhưng chưa được khởi tạo, hoặc là giá trị trả về của một hàm không có return, hoặc có return nhưng không trả về giá trị.
Ví dụ, điều này có thể xảy ra khi bạn khai báo một hàm trong bảng điều khiển của trình duyệt:
function myFunction() {}
> undefined
Một hàm sẽ trả về undefined một cách rõ ràng khi câu lệnh return không trả về giá trị nào:
(function() {
return;
}());
> undefined
Đọc chi tiết: Giải mã JavaScript undefined: Nguyên nhân và cách xử lý
Kiểu dữ liệu của null vs undefiend
Trong JavaScript, để kiểm tra kiểu của một biến, bạn có thể sử dụng toán tử “typeof”.
- Đối với null, kết quả hiển thị sẽ là một object.
var x = null;
console.log(typeof(x));
Ở đây, bạn đã gán giá trị null cho biến x và sau đó kiểm tra kiểu của nó.
- Đối với undefined, kiểu của undefined chính là undefined. Về cơ bản, đây là một kiểu dữ liệu riêng biệt.
Ví dụ như:
var x;
console.log(typeof(x));
Kết quả hiển thị của đoạn mã trên sẽ là undefined. Ở ví dụ trên, đã khai báo biến x mà không gán giá trị nào. Khi chương trình chạy, giá trị undefined sẽ tự động được gán cho biến x.
So sánh null vs undefined trong JavaScript
Việc hiểu rõ sự giống và khác nhau giữa null và undefined không chỉ giúp bạn tránh được các lỗi logic khó phát hiện, mà còn nâng cao kỹ năng viết mã một cách rõ ràng và chính xác hơn. Dưới đây, ITviec sẽ giải đáp chi tiết về các điểm tương đồng và khác biệt giữa hai giá trị này.
Điểm giống nhau giữa null vs undefined
Một số điểm tương đồng giữa null và undefined như sau:
- Cả hai đều biểu thị sự vắng mặt của giá trị.
- Cả hai đều là kiểu dữ liệu nguyên thủy (primitive) trong JavaScript, tức không phải là đối tượng (object) nên không có phương thức hay thuộc tính nào.
- Cả hai đều trả về giá trị false khi được sử dụng trong biểu thức logic (Boolean context), tức là các giá trị “false”.
Tuy cùng là giá trị false trong JavaScript, null và undefined không loose equal (==) với bất kỳ giá trị false nào khác như số 0, chuỗi rỗng (“”, ‘ ‘), hoặc NaN. Giá trị duy nhất mà null được loose equal là undefined hoặc chính nó. Điều này là do cơ chế ép kiểu (type coercion) của toán tử loose equal == trong JavaScript.
var nullVar = null; // Khai báo biến nullVar và gán giá trị null
console.log("Giá trị của biến là ", nullVar); // In ra giá trị của biến
// Kiểm tra nếu null bằng loose equal (==) với undefined
if (nullVar == undefined){
console.log("null loose equal với undefined!");
};
// Kiểm tra nếu null loose equal với các giá trị falsy khác như 0, NaN hoặc chuỗi rỗng
if(nullVar == 0 || isNaN(nullVar) || nullVar == ''){
console.log("null loose equal với các giá trị falsy khác!");
}
else{
console.log("null không loose equal với các giá trị falsy khác!");
};
Kết quả khi chạy:
Giá trị của biến là null
null bằng lỏng với undefined!
null không bằng lỏng với các giá trị falsy khác!
Điểm khác nhau giữa null vs undefined
Dưới đây là một số điểm khác nhau giữa null với undefined trong JavaScript
undefined | null | |
Định nghĩa | Giá trị mặc định mà JavaScript tự động gán cho một biến đã được khai báo nhưng chưa được gán giá tr, một hàm không trả về gì (return không có giá trị), hoặc khi truy cập một property không tồn tại trong object. | Đại diện cho sự vắng mặt có chủ đích của bất kỳ giá trị đối tượng nào. |
Toán tử typeof | Toán tử typeof() trả về undefined cho biến chưa được gán giá trị. Nếu biến chưa khai báo, typeof vẫn trả về undefined thay vì văng lỗi. | Toán tử typeof() trả về object cho biến được gán giá trị là null. |
Khi thực hiện phép toán số học | Trả về NaN khi thực hiện các phép toán số học. | Được chuyển thành 0 và sau đó thực hiện phép toán. |
Có phải là giá trị gán không? | Không, vì không có giá trị nào được gán cho biến, nên biến trở thành undefined. | Có, vì khi chúng ta gán null cho một biến, nó là một giá trị gán. |
Ở nghĩa chính xác, null biểu thị một giá trị được xác định một cách có chủ đích là “trống”, trong khi undefined biểu thị việc chưa được gán bất kỳ giá trị nào.
null và undefined bằng nhau khi loose equal (==), nhưng không bằng nhau khi so sánh nghiêm ngặt (strictly equal) (===). Toán tử loose equal sẽ thực hiện ép kiểu hai toán hạng nếu chúng khác kiểu, trong đó null chỉ được xem là bằng với undefined, và ngược lại. Trong khi đó, toán tử so sánh chặt chẽ sẽ xem hai giá trị có kiểu dữ liệu khác nhau là không bằng nhau.
null == undefined
> true
null === undefined
> false
Không giống như từ khóa dự trữ null, undefined là một thuộc tính của đối tượng toàn cục (global object). Đây là một quyết định thiết kế được đưa ra từ rất sớm trong quá trình phát triển JavaScript, và nó đã cho phép các trình duyệt đời cũ ghi đè giá trị của undefined hoàn toàn.
Trong các trình duyệt hiện đại, việc sử dụng undefined như một tên biến (identifier) trong các phạm vi không toàn cục (non-global scope) vẫn có thể khiến giá trị của undefined bị ghi đè trong phạm vi khai báo đó.
Ngoài ra, bạn cần lưu ý không bao giờ sử dụng undefined làm tên biến. Việc này có thể gây ra hành vi không mong muốn và dễ gây nhầm lẫn cho những người khác đọc hoặc bảo trì mã của bạn sau này.
Ví dụ
Để hiểu rõ hơn về sự khác nhau giữa null với undefined, bạn có thể tham khảo qua ví dụ dưới đây:
var exp = null;
var base = 2;
console.log(base ** exp); // 2 mũ 0 = 1
Kết quả hiển thị sẽ là 1.
Như đã biết, khi một biến được khởi tạo với giá trị null và thực hiện phép toán số học trên đó, null sẽ được chuyển thành 0. Trong ví dụ này, tính lũy thừa của base, với số mũ (exp) là 0 nên kết quả là 1.
Ví dụ 2:
function areaFunction(l, b, h) {
var area = l * b * h;
console.log(area); // NaN
console.log(h); // undefined
}
areaFunction(19, 78);
Kết quả:
NaN
Undefined
Bởi vì không truyền đối số cho biến h, nên giá trị mặc định của nó là undefined. Khi thực hiện phép toán số học với một biến có giá trị undefined, kết quả sẽ là NaN (Not a Number).
Cách sử dụng và kiểm tra null hoặc undefined trong JavaScript
Khi nào nên dùng null hoặc undefined?
Vì undefined là giá trị mặc định được JavaScript gán cho các biến chưa được khởi tạo, nếu bạn muốn chỉ rõ rằng không có một “giá trị giao dịch” (deal) nào, nên sử dụng null vì undefined vẫn là giá trị hợp lệ trong một số API hoặc mặc định JS.
Cách kiểm tra biến có phải là null hoặc undefined
Để kiểm tra xem một biến có giá trị hay không trước khi tiếp tục thực hiện chương trình, bạn có thể sử dụng loose equa == null để kiểm tra xem biến đó có là null hoặc undefined hay không.
Ví dụ, trong đoạn mã sau, hàm assignVal() sẽ kiểm tra xem biến num có đang là undefined hoặc null không, và chỉ gán giá trị người dùng đưa vào nếu biến num chưa được khởi tạo. Do đó, giá trị trong biến c sẽ không bị thay đổi bởi hàm này:
let assignVal = (num,val) => {
// nếu num là null hoặc undefined, gán giá trị mới
// nếu không, giữ nguyên giá trị cũ
if( num == null){
num = val;
}
return num;
};
var a;
var b = null;
var c = 0;
a = assignVal(a,100);
b = assignVal(b,50);
c = assignVal(c,80);
console.log("a =", a,",b =",b,",c=",c);
/* Kết quả:
a = 100 ,b = 50 ,c = 0
*/
Tránh lỗi khi biến chưa được khai báo
Nếu bạn cố gắng kiểm tra sự vắng mặt của một giá trị mà biến đó chưa từng được khai báo bằng phương pháp trên, chương trình sẽ ném ra lỗi ReferenceError. Trong những trường hợp như vậy, bạn có thể sử dụng hàm typeof() để kiểm tra xem biến có được khai báo và khởi tạo đúng cách hay chưa bằng câu lệnh sau:
typeof(undeclaredVar) !== "undefined" && undeclaredVar != null
Biểu thức này sẽ trả về false nếu biến undeclaredVar:
- Chưa được khai báo.
- Được khai báo nhưng chưa khởi tạo (undefined).
- Được khai báo nhưng được gán là null hoặc undefined.
Vì vậy, bạn có thể kết luận rằng một biến đã được khai báo đúng cách và có giá trị hợp lệ khi biểu thức trên trả về true.
Câu hỏi thường gặp về null vs undefined
Tại sao null được xem là một kiểu Object trong JavaScript?
Trong JavaScript, khi kiểm tra kiểu dữ liệu của null bằng typeof, kết quả trả về là “object”:
console.log(typeof null); // "object"
Điều này là một bug của JavaScript. Khi JavaScript được phát triển lần đầu vào năm 1995, các giá trị trong ngôn ngữ này được lưu trữ dưới dạng tagged types, trong đó một phần của giá trị nhị phân sẽ chỉ định kiểu dữ liệu.
Cụ thể, null được biểu diễn bằng bit giống như các đối tượng (object), do đó typeof null trả về “object”. Dù đây là một sai sót, nó đã tồn tại quá lâu nên không thể thay đổi mà không phá vỡ các chương trình JavaScript cũ.
Dù typeof null === "object"
, nhưng null không thực sự là một đối tượng, mà là một giá trị nguyên thủy (primitive value) đại diện cho “không có gì”.
Tại sao biểu thức null == undefined lại trả về true?
Trong JavaScript, khi sử dụng toán tử loose equality (==), trình thông dịch sẽ tự động chuyển đổi (type coercion) các giá trị khác kiểu để thực hiện so sánh.
console.log(null == undefined); // true
Cụ thể, theo chuẩn ECMAScript, null và undefined được coi là bằng nhau (equal) khi dùng ==, vì cả hai đều đại diện cho giá trị “không xác định” hoặc “không tồn tại”.
Tuy nhiên, nếu dùng toán tử so sánh (===), thì:
console.log(null === undefined); // false
Vì lúc này, trình thông dịch không thực hiện ép kiểu, và do null là kiểu null, còn undefined là kiểu undefined, nên chúng không bằng nhau.
Biến được gán giá trị null có phải là biến chưa được khởi tạo không?
Không, biến được gán giá trị null không phải là biến chưa được khởi tạo. Khi bạn gán null cho một biến, điều đó có nghĩa là bạn đã chủ động khởi tạo biến đó với giá trị “trống”, thường nhằm mục đích rõ ràng là biến này hiện tại không có giá trị, nhưng sẽ được gán sau.
Ngược lại, undefined thường xảy ra khi:
- Biến được khai báo nhưng chưa được gán giá trị.
- Tham số không được truyền vào khi gọi hàm.
- Hàm không có return, hoặc return không trả về gì.
- Truy cập vào một thuộc tính không tồn tại của một object.
Có thể ghi đè undefined hoặc null không?
Với null, bạn hoàn toàn có thể gán lại giá trị này cho bất kỳ biến nào như một giá trị thông thường, vì null là một hằng số toàn cục chứ không phải từ khóa bị khóa. Tuy nhiên, bạn không thể thay đổi chính bản thân null như một biến, vì nó là từ khóa có ý nghĩa đặc biệt trong JavaScript.
Với undefined, tình huống phức tạp hơn:
- Trong ES3 và các phiên bản cũ, undefined có thể bị ghi đè vì nó chỉ là một biến toàn cục không bị bảo vệ.
- Từ ES5 trở đi, undefined đã trở thành read-only, nên bạn không thể ghi đè giá trị này một cách bình thường.
Tổng kết
Null vs undefined tuy giống nhau ở chỗ đại diện cho giá trị “trống” trong JavaScript, nhưng lại khác nhau về ý nghĩa và cách sử dụng. undefined thường xuất hiện khi một biến được khai báo nhưng chưa gán giá trị, trong khi null được lập trình viên gán để chỉ định rõ ràng rằng biến đó “không có giá trị”. Việc phân biệt chính xác sẽ giúp bạn kiểm soát tốt hơn logic chương trình và hạn chế bug trong quá trình phát triển phần mềm.