In JavaScript gibt es 5 grundlegende Datentypen und 1 komplexen Datentyp: Undefiniert, Null, Boolean, Zahl und String; der komplexe Datentyp ist ebenfalls in viele spezifische Typen unterteilt . Typ, wie zum Beispiel: Array, Funktion, Datum usw. Heute besprechen wir, wie man den Typ einer Variablen bestimmt.
Bevor wir die verschiedenen Methoden erläutern, definieren wir zunächst einige Testvariablen, um zu sehen, wie die folgenden Variablentypen fast die Typen analysieren können, die wir üblicherweise in der tatsächlichen Codierung verwenden.
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. Art der Erkennung verwenden
Was wir normalerweise am häufigsten verwenden, ist die Verwendung von typeof zum Erkennen von Variablentypen. Dieses Mal verwenden wir auch typeof, um den Typ der Variablen zu ermitteln:
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
Den Ausgabeergebnissen nach zu urteilen, werden arr, json, nul, date, reg, error alle als Objekttypen erkannt, und andere Variablen können korrekt erkannt werden. Wenn Sie feststellen müssen, ob eine Variable vom Typ Zahl, Zeichenfolge, Boolescher Wert, Funktion, Undefiniert oder JSON ist, können Sie zur Bestimmung typeof verwenden. Der Typ anderer Variablen, einschließlich Null, kann nicht bestimmt werden.
Außerdem kann typeof nicht zwischen Array- und JSON-Typen unterscheiden. Denn bei Verwendung der Variable typeof geben sowohl Array- als auch JSON-Typen Objekte aus.
2. Instanzerkennung verwenden
In JavaScript wird der Typeof-Operator häufig verwendet, um den Typ einer Variablen zu bestimmen. Bei der Verwendung des Typeof-Operators tritt ein Problem auf, wenn Referenztypen zum Speichern von Werten verwendet werden. Unabhängig davon, auf welchen Objekttyp verwiesen wird, gibt er „Objekt“ zurück ". ECMAScript führt eine weitere Java-Operatorinstanz ein, um dieses Problem zu lösen. Der Instanz-Operator ähnelt dem Typ-Operator und wird verwendet, um den Typ des verarbeiteten Objekts zu identifizieren. Im Gegensatz zur Methode „typeof“ muss der Entwickler bei der Methode „instanceof“ explizit bestätigen, dass das Objekt von einem bestimmten Typ ist. Zum Beispiel:
function Person(){ } var Tom = new Person(); console.log(Tom instanceof Person); // true
Schauen wir uns noch einmal das folgende Beispiel an:
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 kann auch mehrstufige Vererbungsbeziehungen erkennen.
Okay, verwenden wir „instanceof“, um die oben genannten Variablen zu erkennen:
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
Aus den obigen Laufergebnissen können wir ersehen, dass der Typ von num, str und bool nicht erkannt wurde, aber wenn wir num mit der folgenden Methode erstellen, kann der Typ erkannt werden:
var num = new Number(123); var str = new String('abcdef'); var boolean = new Boolean(true);
Gleichzeitig müssen wir auch sehen, dass und und nul erkannte Objekttypen sind, sodass sie true ausgeben, da es in js keine globalen Typen von Undefiniert und Null gibt. Sowohl und als auch nul gehören zum Objekttyp. Sie sind also wahr.
3. Verwenden Sie den Konstruktor, um
zu erkennenWenn wir „instanceof“ zum Erkennen von Variablentypen verwenden, können wir die Typen „Zahl“, „Zeichenfolge“ und „Bool“ nicht erkennen. Deshalb müssen wir einen anderen Weg finden, dieses Problem zu lösen.
Konstruktor ist ursprünglich eine Eigenschaft des Prototypobjekts, die auf den Konstruktor verweist. Wenn jedoch kein Instanzattribut oder keine Instanzmethode für das Instanzobjekt vorhanden ist, wird entsprechend der Reihenfolge, in der das Instanzobjekt nach Attributen sucht, in der Prototypenkette gesucht. Daher kann das Instanzobjekt auch das Konstruktorattribut verwenden.
Lassen Sie uns zunächst den Inhalt von num.constructor ausgeben, also wie der Konstruktor einer Variablen vom numerischen Typ aussieht:
Funktionsnummer() { [nativer Code] }
Wir können sehen, dass es auf den Konstruktor von Number zeigt. Daher können wir num.constructor==Number verwenden, um zu bestimmen, ob num vom Typ Number ist:
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
Aus den Ausgabeergebnissen können wir ersehen, dass außer undefiniert und null der Typ anderer Variablentypen mithilfe des Konstruktors bestimmt werden kann.
Die Verwendung des Konstruktors ist jedoch nicht sicher, da das Konstruktorattribut geändert werden kann, was dazu führen kann, dass die erkannten Ergebnisse falsch sind, zum Beispiel:
function Person(){ } function Student(){ } Student.prototype = new Person(); var John = new Student(); console.log(John.constructor==Student); // false console.log(John.constructor==Person); // true
Im obigen Beispiel wird der Konstruktor im Student-Prototyp so geändert, dass er auf Person zeigt, was dazu führt, dass der tatsächliche Konstruktor des Instanzobjekts John nicht erkannt werden kann.
Gleichzeitig muss bei Verwendung von Instanz von und Konstruktor das zu beurteilende Array auf der aktuellen Seite deklariert werden! Beispielsweise verfügt eine Seite (übergeordnete Seite) über einen Frame, und in diesem Frame wird auf eine Seite (untergeordnete Seite) verwiesen, die einer Variablen der übergeordneten Seite zugewiesen wird wird beurteilt, Array == object.constructor; gibt false zurück; Grund:
1. Das Array besteht aus Referenzdaten. Während des Übertragungsvorgangs erfolgt nur die Übertragung der Referenzadresse.
2. Die Adresse, auf die das native Array-Objekt jeder Seite verweist, ist unterschiedlich. Der entsprechende Konstruktor des auf der Unterseite deklarierten Arrays ist das Array-Objekt der übergeordneten Seite, und das verwendete Array ist nicht gleich Array von Unterseiten; denken Sie daran, sonst wird es schwierig, das Problem aufzuspüren!
4. Verwenden Sie Object.prototype.toString.call
Kümmern wir uns nicht darum, was das ist, werfen wir zunächst einen Blick darauf, wie es Variablentypen erkennt:
console.log( Object.prototype.toString.call(num), Object.prototype.toString.call(str), Object.prototype.toString.call(bool), Object.prototype.toString.call(arr), Object.prototype.toString.call(json), Object.prototype.toString.call(func), Object.prototype.toString.call(und), Object.prototype.toString.call(nul), Object.prototype.toString.call(date), Object.prototype.toString.call(reg), Object.prototype.toString.call(error) ); // '[object Number]' '[object String]' '[object Boolean]' '[object Array]' '[object Object]' // '[object Function]' '[object Undefined]' '[object Null]' '[object Date]' '[object RegExp]' '[object Error]'
从输出的结果来看,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
Kommt es Ihnen bekannt vor, wenn Sie die Ausgabe sehen? Ja, es ist der zweite Parameter der Ergebnisausgabe mit Object.prototype.toString.call (Variable) oben.
Vergleichen wir zunächst die Erkennungsergebnisse aller oben genannten Methoden. Die horizontale Reihe ist die verwendete Erkennungsmethode und die vertikale Reihe ist jede Variable:
类型判断 | Typ | instanceof | Konstrukteur | toString.call | $.type |
Anzahl | Nummer | falsch | wahr | [Objektnummer] | Nummer |
str | Zeichenfolge | falsch | wahr | [Objektzeichenfolge] | Zeichenfolge |
bool | boolean | falsch | wahr | [Objekt Boolean] | boolean |
arr | Objekt | wahr | wahr | [Objektarray] | Array |
json | Objekt | wahr | wahr | [Objekt Objekt] | Objekt |
Funktion | Funktion | wahr | wahr | [Objektfunktion] | Funktion |
und | undefiniert | falsch | - | [Objekt undefiniert] | undefiniert |
nul | Objekt | falsch | - | [Objekt Null] | null |
Datum | Objekt | wahr | wahr | [Objektdatum] | Datum |
reg | Objekt | wahr | wahr | [object RegExp] | regexp |
Fehler | Objekt | wahr | wahr | [Objektfehler] | Fehler |
Vorteile | Einfach zu bedienen und kann Ergebnisse direkt ausgeben | Kann komplexe Typen erkennen | Grundsätzlich in der Lage, alle Typen zu erkennen | Alle Typen erkennen | - |
Nachteile | Zu wenige Typen erkannt | Basistypen können nicht erkannt werden und können keine Iframes überschreiten | Iframes können nicht überquert werden und der Konstruktor kann leicht geändert werden | Unter IE6 sind undefiniert und null beide Objekte | - |
这样对比一下,就更能看到各个方法之间的区别了,而且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即可。