Type checking trong JavaScript
Bài đăng này đã không được cập nhật trong 6 năm
MỞ ĐẦU
Javascript là ngôn ngữ không cần chỉ rõ kiểu dữ liệu khi khai báo biến. Nếu phải định rõ kiểu cho biến sẽ làm giảm phần lớn sức mạnh của Js, tuy nhiên trong nhiều trường hợp, việc hiểu rõ các cách kiểm tra kiểu dữ liệu của biến vẫn rất cần thiết. Có nhiều cách để kiểm tra kiểu dữ liệu trong JavaScript, tuy nhiên trong bài viết này, mình xin giới thiệu 4 cách: toán tử typeof
, toán tử instanceof
, constructor property
và phương thức toString
của Object.
1. typeof operator
Toán tử typeof
trong JavaScript trả về một chuỗi mô tả kiểu dữ liệu của bất kỳ toán hạng đầu vào nào. Trong ECMAScript 5
, có 6 giá trị có thể được trả về khi thực hiện type checking:
typeof 'str'; // "string"
typeof 10; // "number"
typeof true; // "boolean"
typeof {}; // "object"
typeof function(){}; // "function"
typeof undefined; // "undefined"
Tính nhất quán và độ tin cậy của toán tử này là không cao, ta có thể gặp phải vấn đề khi sử dụng toán tử này với các kiểu dữ liệu không phải là một trong những kiểu bên trên, ví dụ như là mảng
, null
các loại custom Object. Hơn nữa, type checking theo cách này có rùi ro do sẽ phải so sánh chuỗi (case sensitive versuse insensive hoặc lỗi chính tả).
typeof null; // "object"
typeof []; // "object"
typeof new String('str'); // "object"
typeof new function Custom(){}; // "object"
typeof {} === 'Object'; // false
typeof {} === 'objcet'; // false
2. instanceof operator
Toán tử instanceof
so sánh hai giá trị (một biến và một function) bằng cách kiểm tra chuỗi nguyên mẫu (prototype chain) của biến với nguyên mẫu của function object. Vì toán hạng thứ 2 có thể là bất cứ function nào mà chings ta muốn, nên instanceof
có thể được sử dụng để kiểm tra các custom types
nữa. Hơn nữa, bởi instanceof
sử dụng toán hạng là một function thay vì một chuỗi, do đó, nếu ta có vô tình gõ nhầm thì trình biên dịch sẽ thông báo lỗi ngay.
{} instanceof Object; // true
[] instanceof Array; // true
(function(){}) instanceof Function; // true
var Foo = function(){};
new Foo() instanceof Foo; // true
new Foo() instanceof Doo; // ReferenceError: Doo is not defined
Kiểm tra chuỗi nguyên mẫu của đối tượng thì khá hữu ích, tuy nhiên instanceof
sẽ luôn luôn trả về false
cho các kiểu dữ liệu nguyên thủy (chuỗi, number, booleans, null và undefined) bởi chúng không phải là đối tượng và do đó không có nguyên mẫu.
'str' instanceof String; // false
9 instanceof Number; // false
true instanceof Boolean; // false
null instanceof Object; // false
undefined instanceof Object; // false
Mặc dù chúng ta null
hoặc undefined
không thể là toán hạng thứ 2 của toán tử instanceof (vì chúng không phải là function), ta vẫn có thể dễ dàng kiểm tra null và undefined với toán tử ===
.
undefined instanceof undefined; // TypeError: Expecting a function in instanceof check, but got undefined
null instanceof null; // TypeError: Expecting a function in instanceof check, but got null
undefined === undefined; // true
null === null; // true
3. constructor property
Các đối tượng kế thừa constructor
property từ nguyên mẫu của chúng, chúng ta có thể sử dụng nó để kiểm tra kiểu của biến mà không phải kiểm tra toàn bộ chuỗi nguyên mẫu. Giống như instanceof
, ta đang kiểm tra function object, vì vậy chúng ta có thể kiểm tra custom function.
({}).constructor === Object; // true
/regex/.constructor === RegExp; // true
(new Date()).constructor === Date; // true
[].constructor === Array; // true
[] instanceof Array; // true
[].constructor === Object; // false
[] instanceof Object; // true
var Custom = function(){};
(new Custom()).constructor === Custom; // true
Cách này cũng áp dụng với các kiểu dữ liệu nguyên thủy, bởi JavaScript sẽ wrap các giá trị này vào trong các class Number, String và Boolean khi chúng ta cố gắng truy cập vào một thuộc tính trên chúng.
(9).constructor === Number; // true
'str'.constructor === String; // true
true.constructor === Boolean; // true
Tuy nhiên, vì cách này truy cập trực tiếp vào property thay vì thông qua method, nên có thể gặp tình huống vô tình sửa đổi giá trị của property
var Custom = function(){};
var custom = new Custom();
custom.constructor = null;
custom.constructor === Custom; // false
custom = null;
custom.constructor === Custom; // TypeError: Cannot read property 'constructor' of null
custom === null; // true
4. Object.prototype.toString method
Cách này thì khắc phục được nhiều vấn đề của các phương pháp bên trên. Object.prototype.toString
sẽ trả về một chuỗi theo form "[object Type]", và nó có thể được so sánh tương tự như cách dùng typeof
.
Không may là ta vẫn phải so sánh chuỗi, và các custom object sẽ trả về chuỗi "[object Object]".
[1,2,3].toString(); // "1,2,3"
Object.prototype.toString.call([1,2,3]); // "[object Array]"
Object.prototype.toString.call(new Date())
.slice(8, -1) === 'Date'; // true
Object.prototype.toString.call(
new (function Custom(){})); // "[object Object]"
Giống như constructor
, method này sẽ wrap các kiểu dữ liệu nguyên thủy vào các đối tượng tương ứng của chúng. Thêm nữa, phương pháp này còn áp dụng được cho cả trường hợp null
hoặc undefined
.
Object.prototype.toString.call('str'); // "[object String]"
Object.prototype.toString.call(10); // "[object Number]"
Object.prototype.toString.call(false); // "[object Boolean]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
KẾT LUẬN
I would be presumptuous to claim there is one best way to check types in JavaScript. In truth, there are many valid ways, each with their pros and cons, and each better suited for specific situations and projects. Having a better understanding of these options gives us power to make an informed decision that’s best for our code. For convenience, here is a table summarizing a few properties of each approach. Không thể khẳng định đâu là cách tốt nhất để kiểm tra kiểu dữ liệu trong JavaScript. Trong thực tế, có rất nhiều cách, mỗi cách đều có ưu và khuyết điểm riêng, và phù hợp hơn cho từng tình huống cụ thể của dự án. Nắm rõ càng nhiều phương pháp, ta lại càng có thể lựa chọn phương pháp phù hợp nhất với mình. Để thuận tiện, dưới đây là một bảng tóm tắt một vài tính chất của mỗi cách trên
typeof | instanceof | constructor | tostring | |
---|---|---|---|---|
Tránh phải so sánh chuỗi | O | O | ||
commonly used | O | O | ||
checks custom classes | O | O | ||
check null trực tiếp | O | |||
check undefined trực tiếp | O | O | ||
hoạt động trong trường hợp window khác nhau (1) | O | O |
Chú thích
(1) Mỗi window / frame lại tạo instance unique cho mỗi đối tượng build-in. Vì vậy nếu chúng ta so sánh Array window này với Array ở window khác, 2 giá trị này sẽ không bằng nhau.
Nguồn tham khảo
All rights reserved