typeof và instanceof
Bài đăng này đã không được cập nhật trong 6 năm
Giới thiệu
Chắc hẳn đôi lúc bạn cũng đau đầu vì việc validate kiểu dữ liệu đầu vào cho function ở javascript đúng không? 2 hàm được sử dụng để check kiểu dữ liệu là typeof và instanceof. Trong bài viết này mình sẽ giới thiệu một số cách để làm cho hàm instanceof của javascript có thể làm được nhiều hơn việc check type so với hiện tại.
Vấn đề
Sự phức tạp của typeof và instanceof
Trong javascript, khi kiểm tra kiểu dữ liệu của 1 giá trị, có những cách thông thường là
- Dùng typeof kiểm tra nếu giá trị đó là kiểu nguyên thuỷ (primitive type)
if (typeof value === 'string') ...
- Dùng instanceof để kiểm tra nếu giá trị là instance của 1 class hoặc constructor của một function
if (value instanceof Map) ···
Điều này không thực sự lý tưởng vì bạn phải hiểu sự khác biệt của kiểu dữ liệu nguyên thuỷ và dữ liệu tham chiếu, điều này có thể gây bối rối và đôi khi gây lỗi.
Thêm nữa là vài thứ không minh bạch trong JS có thể làm vấn đề trở nên khá phức tạp, ví dụ
- typeof null là 'object', không phải là 'null'. Cái này có thể coi là 1 bug
- typeof phân biệt object và function (mà trong JS thì function cũng là 1 object)
> typeof {}
'object'
> typeof function () {}
'function'
Sự không rõ ràng này, cùng với những thứ mơ hồ ở trên, làm cho việc kiểm tra loại dữ liệu của 1 biến không phải object (tức là primary type) trở nên không đơn giản thông qua typeof
- Không phải tất cả các object đều là instance của Object
> Object.create(null) instanceof Object
false
Khắc phục
1. Tạo instanceof cho kiểu dữ liệu nguyên thuỷ (primitive values)
Ví dụ tạo ra 1 class để check xem có phải là kiểu dữ liệu số (number) không. Chúng ta tạo ra 1 class PrimitiveNumber, đoạn code dưới đây đơn giản return là kiểu số nếu typeof x === 'number' trả về true, chỉ cần implement 1 static method cho PrimitiveNumber mà key là symbol Symbol.hasInstance
class PrimitiveNumber {
static [Symbol.hasInstance](x) {
return typeof x === 'number';
}
}
console.log(123 instanceof PrimitiveNumber); // true
2. Kiểm tra bằng cách dùng TypeRight library
Có 1 thư viện hỗ trợ việc kiểm tra type khá đầy đủ và đơn giản đó chính là TypeRight library, các bạn có thể xem thêm ở đây https://github.com/rauschma/type-right Thư viện này sử dụng cách tiếp cận của ví dụ trên để code ra chức năng của những class dứới. Mục đích của nó là để hàm instanceof hoạt động 1 cách trơn tru mà không phải suy nghĩ quá nhiều là dữ liệu đầu vào là loại primitive hay object.
PrimitiveUndefined PrimitiveNull PrimitiveBoolean PrimitiveNumber PrimitiveString PrimitiveSymbol Với sự hỗ trợ của TypeRight, bạn có thể kiểm tra nếu biến có kiểu dữ liệu input đúng với hàm đã viết, nó sẽ throw error nếu dữ liệu input sai kiểu
import * as tr from 'type-right';
function dist(x, y) {
tr.force(x, tr.PrimitiveNumber, y, tr.PrimitiveNumber);
return Math.hypot(x, y);
}
dist(3, 4); // 5
dist(3, undefined); // TypeError
3. Kiểm tra bằng Builtin
Builtin.is và Builtin.typeOf được giới thiệu bởi James M.Snell dùng cho việc kiểu tra kiểu dữ liệu. Các bạn có thể tham khảo ở đây https://github.com/jasnell/proposal-istypes
Builtin.is(value1, value2) kiểm tra nếu value1 và value2 cùng trỏ đến cùng 1 builtin constructor
> Builtin.is(Date, vm.runInNewContext('Date'))
true
> Builtin.is(Date, Date)
true
Builtin.typeOf() có thể là sự mở rộng của typeof mà dùng được cho cả primitive values và built-in classes
Builtin.typeOf(undefined); // 'undefined'
Builtin.typeOf(null); // 'null'
Builtin.typeOf(123); // 'number'
Builtin.typeOf(new Number()); // 'Number'
Builtin.typeOf([]); // 'Array'
Builtin.typeOf(new Map()); // 'Map'
// The builtin counts, not the user-defined class
class MyArray extends Array {}
Builtin.typeOf(new MyArray()); // 'Array'
Kết bài
Như vậy là mình đã giới thiệu xong các phương pháp có thể dùng để thay thế hay bổ sung vào phương thức typeof và instanceof hiện tại của Javascript. Hy vọng nó sẽ có ích cho các bạn.
Bài viết có sử dụng nguồn từ http://2ality.com/2017/08/type-right.html
All rights reserved