Operator instanceof
memungkinkan kita untuk memeriksa apakah suatu object milik class tertentu. instanceof
juga memperhatikan inheritance.
Pengecekan seperti itu mungkin diperlukan dalam beberapa kasus. Di sini kita akan menggunakannya untuk membangun fungsi polymorphic, yang memperlakukan argumen secara berbeda bergantung pada tipenya.
Operator instanceof
Sintaksnya adalah:
obj instanceof Class
Akan mengembalikan true
jika obj
dimiliki oleh Class
atau kelas turunannya.
Misalnya:
class Rabbit {}
let rabbit = new Rabbit();
// apakah ini merupakan object dari kelas Rabbit?
alert( rabbit instanceof Rabbit ); // true
Itu juga bekerja dengan fungsi constructor:
// dari pada class
function Rabbit() {}
alert( new Rabbit() instanceof Rabbit ); // true
…Dan kelas bawaan seperti Array
:
let arr = [1, 2, 3];
alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true
Harap dicatat bahwa arr
juga termasuk dalam kelas Object
. Itu karena Array
secara prototipikal mewarisi dariObject
.
Normalnya, instanceof
memeriksa rantai prototype untuk pemeriksaan. Kita juga dapat menyetel custom logic dalam static method Symbol.hasInstance
.
Algoritma obj instanceof Class
bekerja kurang lebih sebgai berikut:
-
Jika terdapat static method
Symbol.hasInstance
, maka panggil saja:Class[Symbol.hasInstance](obj)
. Itu akan mengembalikantrue
ataufalse
, selesai. Begitulah cara kita bisa menyesuaikan perilaku dariinstanceof
.Sebagai contoh:
// menyiapkan instanceOf yang berasumsi // apapun yang memiliki properti canEat adalah binatang class Animal { static [Symbol.hasInstance](obj) { if (obj.canEat) return true; } } let obj = { canEat: true }; alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) dipanggil
-
Kebanyakan kelas tidak memiliki
Symbol.hasInstance
. Dalam kasus ini, logika standar digunakan:obj instanceOf Class
Memeriksa apakahClass.prototype
sama dengan salah satu prototype dalam rantai prototypeobj
.Dengan kata lain, bandingkan satu sama lain:
obj.__proto__ === Class.prototype? obj.__proto__.__proto__ === Class.prototype? obj.__proto__.__proto__.__proto__ === Class.prototype? ... // jika jawabannya true, return true // jika tidak, jika kita mencapai ujung rantai, return false
Pada contoh diatas
rabbit.__proto__ === Rabbit.prototype
, sehingga akan memberikan jawaban segera.Dalam kasus inheritance, kesamaan akan berada pada langkah kedua:
class Animal {} class Rabbit extends Animal {} let rabbit = new Rabbit(); alert(rabbit instanceof Animal); // true // rabbit.__proto__ === Rabbit.prototype // rabbit.__proto__.__proto__ === Animal.prototype (match!)
Berikut ilustrasi tentang perbandingan rabbit instanceof Animal
dengan Animal.prototype
:
Omong-omong, terdapat juga method objA.isPrototypeOf(objB), yang mengembalikan true
jika objA
berada di suatu tempat dalam rantai prototypes untuk objB
. Jadi pengujian obj instanceof Class
bisa dirumuskan sebagai Class.prototype.isPrototypeOf(obj)
.
Ini lucu, tetapi constructor Class
itu sendiri tidak ikut dalam pemeriksaan! Hanya rangkaian dari prototype dan Class.prototype
yang penting.
Itu bisa menimbulkan konsekuensi yang menarik ketika properti prototype
diubah setelah objek dibuat.
Seperti:
function Rabbit() {}
let rabbit = new Rabbit();
// mengubah prototype
Rabbit.prototype = {};
// ...bukan kelinci lagi!
alert( rabbit instanceof Rabbit ); // false
Bonus: Object.prototype.toString untuk tipe
Kita tahu bahwa plain object akan diubah menjadi string sebagai [object Object]
:
let obj = {};
alert(obj); // [object Object]
alert(obj.toString()); // sama
Itulah implementasi dari toString
. Tetapi ada fitur tersembunyi yang membuat toString
menjadi lebih powerful dari itu. Kita bisa menggunakannya sebagai perluasan dari typeof
dan alternatif untuk instanceof
.
Terdengar aneh? Tentu. Mari kita cari tahu.
Dengan spesifikasi, toString
bawaan dapat diekstrak dari object dan dijalankan dalam konteks nilai lainnya. Dan hasilnya tergantung pada nilai tersebut.
- Untuk angka, akan menjadi
[object Number]
- Untuk boolean, akan menjadi
[object Boolean]
- Untuk
null
:[object Null]
- Untuk
undefined
:[object Undefined]
- Untuk array:
[object Array]
- …dll (dapat disesuaikan).
Mari kita tunjukkan:
// copy toString method kedalam sebuah variabel
let objectToString = Object.prototype.toString;
// tipe apa ini?
let arr = [];
alert( objectToString.call(arr) ); // [object Array]
Disini kita gunakan call seperti dijelaskan dalam bab Decorators dan forwarding, call/apply untuk menjalankan fungsi objectToString
dalam konteks this=arr
.
Secara internal, algoritme toString
memeriksa this
dan mengembalikan hasil yang sesuai. Contoh lainnya:
let s = Object.prototype.toString;
alert( s.call(123) ); // [object Number]
alert( s.call(null) ); // [object Null]
alert( s.call(alert) ); // [object Function]
Symbol.toStringTag
Perilaku object toString
dapat disesuaikan dengan menggunakan properti objek khusus Symbol.toStringTag
.
Sebagai contoh:
let user = {
[Symbol.toStringTag]: "User"
};
alert( {}.toString.call(user) ); // [object User]
Untuk sebagian besar objek yang spesifik pada environment, terdapat properti seperti itu. Berikut beberapa contoh untuk browser yang spesifik:
// toStringTag untuk objek dan kelas yang spesifik pada environtment:
alert( window[Symbol.toStringTag]); // Window
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest
alert( {}.toString.call(window) ); // [object Window]
alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
Dapat dilihat, hasilnya persis Symbol.toStringTag
(jika ada), digabungkan ke dalam [object ...]
.
Pada akhirnya kami memiliki “typeof on steroids” yang tidak hanya akan berfungsi untuk tipe data primitif, tetapi juga untuk objek bawaan dan bahkan dapat disesuaikan.
Kita dapat menggunakan {}.toString.call
daripada instanceof
untuk objek bawaan ketika ingin mendapatkan tipe sebagai string daripada hanya untuk diperiksa.
Ringkasan
Mari kita rangkum metode pengecekan tipe yang kita ketahui:
bekerja pada | mengembalikan | |
---|---|---|
typeof |
primitif | string |
{}.toString |
primitif, objek bawaan, objek dengan Symbol.toStringTag |
string |
instanceof |
objek | true/false |
Dapat kita lihat, {}.toString
secara teknis “lebih advanced” typeof
.
Dan operator instanceof
akan lebih berguna ketika kita bekerja dengan hirearki kelas dan ingin memeriksa kelas yang memperhatikan inheritance.