07/09/2018, 18:06

typeof và instanceof

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 ...

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à typeofinstanceof.
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.

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

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'

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

0