Dalam JavaScript, terdapat 5 jenis data asas dan 1 jenis data kompleks Jenis data asas ialah: Undefined, Null, Boolean, Number dan String jenis data kompleks ialah Object, dan Object juga dibahagikan kepada banyak jenis tertentu . Jenis, seperti: Tatasusunan, Fungsi, Tarikh, dsb. Hari ini kita akan membincangkan cara menentukan jenis pembolehubah.
Sebelum menerangkan pelbagai kaedah, kami terlebih dahulu mentakrifkan beberapa pembolehubah ujian untuk melihat cara kaedah seterusnya boleh menghuraikan jenis pembolehubah berikut hampir termasuk jenis yang biasa kami gunakan dalam pengekodan sebenar.
var num = 123; var str = 'abcdef'; var bool = true; var arr = [1, 2, 3, 4]; var json = {name:'wenzi', age:25}; var func = function(){ console.log('this is function'); } var und = undefined; var nul = null; var date = new Date(); var reg = /^[a-zA-Z]{5,20}$/; var error= new Error();
1. Gunakan jenis pengesanan
Apa yang selalu kami gunakan ialah menggunakan typeof untuk mengesan jenis pembolehubah. Kali ini, kami juga menggunakan typeof untuk mengesan jenis pembolehubah:
console.log( typeof num, typeof str, typeof bool, typeof arr, typeof json, typeof func, typeof und, typeof nul, typeof date, typeof reg, typeof error ); // number string boolean object object function undefined object object object object
Berdasarkan hasil keluaran, arr, json, nul, date, reg, error semuanya dikesan sebagai jenis objek dan pembolehubah lain boleh dikesan dengan betul. Apabila anda perlu menentukan sama ada pembolehubah adalah daripada jenis nombor, rentetan, boolean, fungsi, tidak ditentukan atau json, anda boleh menggunakan typeof untuk menentukan. Jenis pembolehubah lain tidak boleh ditentukan, termasuk null.
Juga, typeof tidak dapat membezakan antara jenis tatasusunan dan json. Kerana apabila menggunakan pembolehubah jenis, kedua-dua tatasusunan dan json jenis objek output.
2. Gunakan pengesanan contoh
Dalam JavaScript, operator jenis sering digunakan untuk menentukan jenis pembolehubah Apabila menggunakan operator jenis, masalah timbul apabila menggunakan jenis rujukan untuk menyimpan nilai Tidak kira jenis objek yang dirujuk, ia mengembalikan "objek " ". ECMAScript memperkenalkan satu lagi contoh operator Java untuk menyelesaikan masalah ini. Operator instanceof adalah serupa dengan operator typeof dan digunakan untuk mengenal pasti jenis objek yang sedang diproses. Tidak seperti kaedah typeof, kaedah instanceof memerlukan pembangun untuk mengesahkan secara eksplisit bahawa objek adalah jenis tertentu. Contohnya:
function Person(){ } var Tom = new Person(); console.log(Tom instanceof Person); // true
Mari lihat contoh berikut sekali lagi:
function Person(){ } function Student(){ } Student.prototype = new Person(); var John = new Student(); console.log(John instanceof Student); // true console.log(John instancdof Person); // true
instanceof juga boleh mengesan perhubungan warisan berbilang peringkat.
Okey, mari gunakan instanceof untuk mengesan pembolehubah di atas:
console.log( num instanceof Number, str instanceof String, bool instanceof Boolean, arr instanceof Array, json instanceof Object, func instanceof Function, und instanceof Object, nul instanceof Object, date instanceof Date, reg instanceof RegExp, error instanceof Error ) // num : false // str : false // bool : false // arr : true // json : true // func : true // und : false // nul : false // date : true // reg : true // error : true
Daripada hasil yang dijalankan di atas, kita dapat melihat bahawa jenis num, str dan bool belum dikesan, tetapi apabila kita mencipta num menggunakan kaedah berikut, jenis itu boleh dikesan:
var num = new Number(123); var str = new String('abcdef'); var boolean = new Boolean(true);
Pada masa yang sama, kita juga perlu melihat bahawa und dan nul dikesan jenis Objek, jadi ia menghasilkan benar, kerana tiada jenis global Undefined dan Null dalam js Kedua-dua und dan nul tergolong dalam jenis Objek, jadi mereka adalah output benar.
3. Gunakan pembina untuk mengesan
Apabila menggunakan instanceof untuk mengesan jenis pembolehubah, kami tidak dapat mengesan jenis nombor, 'rentetan' dan bool. Oleh itu, kita perlu mencari jalan lain untuk menyelesaikan masalah ini.
pembina pada asalnya adalah harta pada objek prototaip, menunjuk kepada pembina. Walau bagaimanapun, mengikut susunan objek contoh mencari atribut, jika tiada atribut contoh atau kaedah pada objek contoh, ia akan dicari pada rantaian prototaip Oleh itu, objek contoh juga boleh menggunakan atribut pembina.
Mari kita keluarkan kandungan num.constructor, iaitu, rupa bentuk pembolehubah jenis angka:
fungsi Nombor() { [kod asli] }
Kita dapat melihat bahawa ia menunjuk kepada pembina Nombor Oleh itu, kita boleh menggunakan num.constructor==Number untuk menentukan sama ada num adalah jenis Number
function Person(){ } var Tom = new Person(); // undefined和null没有constructor属性 console.log( Tom.constructor==Person, num.constructor==Number, str.constructor==String, bool.constructor==Boolean, arr.constructor==Array, json.constructor==Object, func.constructor==Function, date.constructor==Date, reg.constructor==RegExp, error.constructor==Error ); // 所有结果均为true
Walau bagaimanapun, menggunakan pembina adalah tidak selamat, kerana atribut pembina boleh diubah suai, yang akan menyebabkan keputusan yang dikesan menjadi salah, contohnya:
function Person(){ } function Student(){ } Student.prototype = new Person(); var John = new Student(); console.log(John.constructor==Student); // false console.log(John.constructor==Person); // true
Pada masa yang sama, apabila menggunakan instanceof dan constructor, tatasusunan yang dinilai mesti diisytiharkan pada halaman semasa! Sebagai contoh, halaman (halaman induk) mempunyai bingkai, dan halaman (halaman anak) dirujuk dalam bingkai Tatasusunan diisytiharkan dalam halaman anak dan diberikan kepada pembolehubah halaman induk dinilai, Array == object.constructor;
1. Array ialah data rujukan Semasa proses pemindahan, ia hanyalah pemindahan alamat rujukan.
2. Alamat yang dirujuk oleh objek asli Array setiap halaman adalah berbeza Pembina tatasusunan yang sepadan yang diisytiharkan pada sub-halaman ialah objek Array bagi halaman induk membuat pertimbangan, dan Array yang digunakan ialah tidak sama dengan Array subhalaman; jika tidak, ia akan menjadi sukar untuk mengesan masalah!
4. Gunakan Object.prototype.toString.call
Mari kita tidak peduli tentang perkara ini, mari kita lihat dahulu cara ia mengesan jenis pembolehubah:
从输出的结果来看,Object.prototype.toString.call(变量)输出的是一个字符串,字符串里有一个数组,第一个参数是Object,第二个参数就是这个变量的类型,而且,所有变量的类型都检测出来了,我们只需要取出第二个参数即可。或者可以使用Object.prototype.toString.call(arr)=="object Array"来检测变量arr是不是数组。
我们现在再来看看ECMA里是是怎么定义Object.prototype.toString.call的:
上面的规范定义了Object.prototype.toString的行为:首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于”[object Array]”的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。
5. jquery中$.type的实现
在jquery中提供了一个$.type的接口,来让我们检测变量的类型:
console.log( $.type(num), $.type(str), $.type(bool), $.type(arr), $.type(json), $.type(func), $.type(und), $.type(nul), $.type(date), $.type(reg), $.type(error) ); // number string boolean array object function undefined null date regexp error
Adakah ia berasa biasa apabila anda melihat output? Ya, ia adalah parameter kedua output hasil menggunakan Object.prototype.toString.call (pembolehubah) di atas.
Mula-mula mari kita bandingkan hasil pengesanan semua kaedah di atas Baris mendatar ialah kaedah pengesanan yang digunakan dan baris menegak ialah setiap pembolehubah:
类型判断 | jenis | contoh | pembina | kepadaString.panggilan | $.type |
bilangan | nombor | palsu | benar | [Nombor objek] | nombor |
str | rentetan | palsu | benar | [Rentetan objek] | rentetan |
bool | boolean | palsu | benar | [objek Boolean] | boolean |
arr | objek | benar | benar | [Susun Objek] | tatasusunan |
json | objek | benar | benar | [Objek objek] | objek |
berfungsi | fungsi | benar | benar | [Fungsi objek] | fungsi |
dan | tidak ditentukan | palsu | - | [objek Tidak Ditakrifkan] | tidak ditentukan |
nul | objek | palsu | - | [objek Null] | null |
tarikh | objek | benar | benar | [Tarikh objek] | tarikh |
reg | objek | benar | benar | [objek RegExp] | regexp |
ralat | objek | benar | benar | [Ralat objek] | ralat |
Kelebihan | Mudah digunakan dan boleh mengeluarkan hasil secara langsung | Boleh mengesan jenis kompleks | Pada asasnya dapat mengesan semua jenis | Kesan semua jenis | - |
Keburukan | Terlalu sedikit jenis dikesan | Jenis asas tidak dapat dikesan dan tidak boleh merentas iframe | Tidak boleh menyeberangi iframe, dan pembina mudah diubah suai | Di bawah IE6, undefined dan null adalah kedua-duanya Objek | - |
这样对比一下,就更能看到各个方法之间的区别了,而且Object.prototype.toString.call和$type输出的结果真的很像。我们来看看jquery(2.1.2版本)内部是怎么实现$.type方法的:
// 实例对象是能直接使用原型链上的方法的 var class2type = {}; var toString = class2type.toString; // 省略部分代码... type: function( obj ) { if ( obj == null ) { return obj + ""; } // Support: Android<4.0, iOS<6 (functionish RegExp) return (typeof obj === "object" || typeof obj === "function") ? (class2type[ toString.call(obj) ] || "object") : typeof obj; }, // 省略部分代码... // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); });
我们先来看看jQuery.each的这部分:
// Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); //循环之后,`class2type`的值是: class2type = { '[object Boolean]' : 'boolean', '[object Number]' : 'number', '[object String]' : 'string', '[object Function]': 'function', '[object Array]' : 'array', '[object Date]' : 'date', '[object RegExp]' : 'regExp', '[object Object]' : 'object', '[object Error]' : 'error' }
再来看看type方法:
// type的实现 type: function( obj ) { // 若传入的是null或undefined,则直接返回这个对象的字符串 // 即若传入的对象obj是undefined,则返回"undefined" if ( obj == null ) { return obj + ""; } // Support: Android<4.0, iOS<6 (functionish RegExp) // 低版本regExp返回function类型;高版本已修正,返回object类型 // 若使用typeof检测出的obj类型是object或function,则返回class2type的值,否则返回typeof检测的类型 return (typeof obj === "object" || typeof obj === "function") ? (class2type[ toString.call(obj) ] || "object") : typeof obj; }
当typeof obj === "object" || typeof obj === "function"时,就返回class2type[ toString.call(obj)。到这儿,我们就应该明白为什么Object.prototype.toString.call和$.type那么像了吧,其实jquery中就是用Object.prototype.toString.call实现的,把'[object Boolean]'类型转成'boolean'类型并返回。若class2type存储的没有这个变量的类型,那就返回”object”。
除了”object”和”function”类型,其他的类型则使用typeof进行检测。即number, string, boolean类型的变量,使用typeof即可。