Thứ Sáu, 12 tháng 4, 2013

Kiểm tra kiểu dữ liệu trong javascript

Kiểm tra kiểu dữ liệu trong javascript

Javascript là ngôn ngữ không ràng buộc về kiểu dữ liệu: không cần khai báo kiểu dữ liệu khi khai báo biến, một biến đang thuộc kiểu dữ liệu này có thể bị gán bởi một giá trị thuộc kiểu dữ liệu khác. Để xác định chính xác kiểu của một biến lúc runtime, nhiều khi trong một số hoàn cảnh cụ thể cũng không phải là một chuyện đơn giản.

Sử dụng toán tử typeof


Dùng typeof sẽ đúng với các trường hợp sau:










1typeof // "number"










2typeof "abc" // "string"










3typeof {} // "object"










4typeof true // "boolean"










5typeof undefined // "undefined"










6typeof function(){} // "function"




Nhưng rất tiếc trong các trường hợp sau thì có vẻ không chuẩn:










1typeof [] // "object"










2typeof null // "object"










3typeof new Date() // "object"










4typeof /abc/ // "object"










5typeof new RegExp("abc"// "object"










6typeof new (function UserDefinedObject(){}) // "object"




typeof đều trả về kết quả là object nếu biến đó là kiểu Date, RegExp, HTML DOM, object do người dùng định nghĩa. Những trường hợp trên thì có thể chấp nhận được nhưng mảng mà đặc biệt là null mà lại cho kiểu là object thì khá vô lý.

Sử dụng toán tử instanceof


Dùng instanceof rất tốt với trường hợp biến không phải thuộc kiểu nguyên thủy:










1function UserDefinedObject(){}










2var a = new UserDefinedObject();










3instanceof UserDefinedObject // true










4new Date() instanceof Date // true










5/abc/ instanceof RegExp // true










6new RegExp("abc"instanceof RegExp // true










7[] instanceof Array // true




Rất tiếc instanceof lại không thực hiện được với các giá trị kiểu nguyên thủy như string, number, boolean, null và undefined.










1instanceof Number // false










2true instanceof Boolean // false










3'abc' instanceof String // false




Trong trường hợp này cũng không sợ lắm vì ta có thể dùng typeof để xử lý.

Vấn đề của instanceof khi kiểm tra kiểu của biến tại cửa số khác


Việc sử dụng instanceof để kiểu tra kiểu dữ liệu của biến sẽ gặp vấn đề khi biến đó nằm ở khác cửa số (window) với ngữ cảnh đang kiểm tra. Ví dụ kiểm tra kiểu của một mảng nằm trên iframe, frame hoặc popup window chẳng hạn:










1var iframe = document.createElement('iframe');










2document.body.appendChild(iframe);










3// lấy về tham chiếu đến đối tượng window của iframe










4var iWindow = iframe.contentWindow;










5// tạo ra mạng arr trong iframe










6iWindow.document.write('<script>var arr = [1, 2, 3]</script>');










7iWindow.arr // [1, 2, 3]










8iWindow.arr instanceof Array // false




Nguyên nhân của việc này là browser tạo cho mỗi một window một sandbox riêng, kiểu dữ liệu (class) Array trong window này hoàn toàn độc lập và khác biệt với kiểu (class) Array ở window khác.

Trong trường hợp trên, để kiểm tra ta làm như sau:










1iWindow.arr instanceof iWindow.Array // true




Sử dụng thuộc tính constructor


Một biến x luôn có thể gọi x.constructor để nhận về tên hàm khởi tạo của nó (không áp dụng khi biến bằng null hoặc undefined)










1function Animal(){}










2var a = new Animal();










3a.constructor === Animal // true










4 










5(3).constructor === Number // true










6true.constructor === Boolean // true










7'abc'.constructor === String // true




Sử dụng phương thức Object.prototype.toString


Khi sử dụng Object.prototype.toString ta thu được như sau:










1Object.prototype.toString.call(3) // "[object Number]"










2Object.prototype.toString.call([1, 2, 3]) // "[object Array]"










3Object.prototype.toString.call({}) // "[object Object]"




Cách này chỉ đúng với các kiểu dữ liệu built-in, đối với tất cả các class do người dùng tự định nghĩa thì đều trả về [object Object]










1Object.prototype.toString.call(new Animal()) // "[object Object]"




Trong trường hợp khác ngữ cảnh window, dùng cách này là chính xác trừ duy nhất trường hợp popup window và chạy trên IE










1var pWindow = open("")










2pWindow.document.write('<script>var arr = [1, 2, 3]</script>')










3Object.prototype.toString.call(pWindow.arr) // IE: "[object Object]" còn lại "[object Array]"




Sử dụng phương thức Function.prototype.toString


Cách sử dụng: Function.prototype.toString.call(x.constructor). Đối với các kiểu dữ liệu built-in sẽ ra dạng như sau:










1Function.prototype.toString.call((3).constructor)










2// "function Number() {










3//    [native code]










4// }"




Đối với các class do người dùng tự định nghĩa thì ta thu được chuỗi định nghĩa hàm khởi tạo.
Dựa vào đó ta lấy ra tên của kiểu dữ liệu (class):










1function type(obj){










2    var text = Function.prototype.toString.call(obj.constructor)










3    return text.match(/function (.*)\(/)[1]










4}










5 










6type("abc"); // "String"










7type(3); // "Number"










8type(new Animal()) // "Animal"




Với cách này dùng được cho trường hợp popup window với IE.

Kiểm tra kiểu dữ liệu cho DOM Element


Tôi sẽ sử dụng các cách thức ở trên để kiểm tra kiểu của biến DOM Element:

typeof và instanceof
> var div = document.createElement(‘div’)
> typeof div
Safari 5.0 => object
Firefox 3.6 => object
IE 7.0 => object
IE 8.0 => object
Opera 11.01 => object
> div instanceof Element
Safari 5.0 => true
Firefox 3.6 => true
IE 7.0 => Error: ‘Element’ is undefined
IE 8.0 => true
Opera 11.01 => true
> div instanceof HTMLDivElement
Safari 5.0 => true
Firefox 3.6 => true
IE 8.0 => true
IE 7.0 => Error: ‘HTMLDivElement’ is undefined
Opera 11.01 => true

 
Object.prototype.toString
> Object.prototype.toString.call(div)
Safari 5.0 => [object HTMLDivElement]
Firefox 3.6 => [object HTMLDivElement]
IE 7.0 => [object Object]
IE 8.0 => [object Object]
Opera 11.01 => [object HTMLDivElement]

 
constructor
> div.constructor.toString()
Safari 5.0 => [object HTMLDivElementConstructor]
Firefox 3.6 => [object HTMLDivElement]
IE 7.0 => Error: ‘div.constructor’ is null or not an object
IE 8.0 => [object HTMLDivElement]
Opera 11.01 => function HTMLDivElement() { [native code] }

 
Biến window
> typeof window
Safari 5.0 => object
Firefox 3.6 => object
IE 8.0 => object
IE 7.0 => object
Opera 11.01 => object
> window instanceof Window
Safari 5.0 => ReferenceError: Can’t find variable: Window
Firefox 3.6 => true
IE 8.0 => true
IE 7.0 => Error: ‘Window’ is undefined
Opera 11.01 => ReferenceError: Undefined variable: Window
> Object.prototype.toString.call(window)
Safari 5.0 => [object DOMWindow]
Firefox 3.6 => [object Object]
IE 8.0 => [object Object]
IE 7.0 => [object Object]
Opera 11.01 => [object Window]
> window.constructor
Safari 5.0 => function Object() {
[native code]
}
Firefox 3.6 => function Object() {
[native code]
}
IE 8.0 => [object Window]
IE 7.0 => undefined
Opera 11.01 => function Object() { [native code] }

Kết luận


Việc xác định kiểu của biến trong javascript là tương đối đơn giản trong các trường hợp phổ biến. Nhưng để xác định chính xác trong mọi trường hợp thì không phải là một chuyện dễ dàng. Chúng ta có rất nhiều cách để xác định và phán đoán kiểu dữ liệu và việc vận dụng nên linh hoạt trong các tình huống cụ thể.

1 nhận xét:

  1. At this time I am ready to do my breakfast, once
    having my breakfast coming yet again to read more news.

    Trả lờiXóa