it-swarm.it

Un modo migliore per ottenere il tipo di una variabile Javascript?

C'è un modo migliore per ottenere il tipo di una variabile in JS rispetto a typeof? Funziona bene quando lo fai:

> typeof 1
"number"
> typeof "hello"
"string"

Ma è inutile quando provi:

> typeof [1,2]
"object"
>r = new RegExp(/./)
/./
> typeof r
"function"

Conosco instanceof, ma questo richiede che tu conosca il tipo in anticipo.

> [1,2] instanceof Array
true
> r instanceof RegExp
true

Esiste un modo migliore?

237
Aillyn

Angus Croll ha recentemente scritto un interessante post sul blog -

http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/

Passa attraverso i pro ei contro dei vari metodi quindi definisce un nuovo metodo 'toType' -

var toType = function(obj) {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}
206
ipr101

Puoi provare a utilizzare constructor.name.

[].constructor.name
new RegExp().constructor.name

Come con tutto il codice JavaScript, qualcuno alla fine invariabilmente indica che questo è in qualche modo malvagio, quindi qui c'è un link a una risposta che copre abbastanza bene.

Un'alternativa è usare Object.prototype.toString.call

Object.prototype.toString.call([])
Object.prototype.toString.call(/./)
46
Alex Turpin

Una funzione di acquisizione di tipo ragionevolmente buona è quella utilizzata da YUI3 :

var TYPES = {
    'undefined'        : 'undefined',
    'number'           : 'number',
    'boolean'          : 'boolean',
    'string'           : 'string',
    '[object Function]': 'function',
    '[object RegExp]'  : 'regexp',
    '[object Array]'   : 'array',
    '[object Date]'    : 'date',
    '[object Error]'   : 'error'
},
TOSTRING = Object.prototype.toString;

function type(o) {
    return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
};

Questo acquisisce molte delle primitive fornite da javascript, ma puoi sempre aggiungerne altre modificando l'oggetto TYPES. Nota che typeof HTMLElementCollection in Safari riporta function, ma digita (HTMLElementCollection) restituirà object

38
Nick Husher

Potresti trovare utile la seguente funzione:

function typeOf(obj) {
  return {}.toString.call(obj).split(' ')[1].slice(0, -1).toLowerCase();
}

O in ES7 (commentare se ulteriori miglioramenti)

function typeOf(obj) {
  const { toString } = Object.prototype;
  const stringified = obj::toString();
  const type = stringified.split(' ')[1].slice(0, -1);

  return type.toLowerCase();
}

Risultati:

typeOf(); //undefined
typeOf(null); //null
typeOf(NaN); //number
typeOf(5); //number
typeOf({}); //object
typeOf([]); //array
typeOf(''); //string
typeOf(function () {}); //function
typeOf(/a/) //regexp
typeOf(new Date()) //date
typeOf(new Error) //error
typeOf(Promise.resolve()) //promise
typeOf(function *() {}) //generatorfunction
typeOf(new WeakMap()) //weakmap
typeOf(new Map()) //map

Grazie a @johnrees per avermi informato di: errore, promessa, funzione generatore

25
Vix

Inoltre possiamo cambiare un piccolo esempio da ipr101

Object.prototype.toType = function() {
  return ({}).toString.call(this).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}

e chiama come

"aaa".toType(); // 'string'
14
greymaster

una funzione di linea:

function type(obj) {
    return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/,"$1").toLowerCase()
}

questo dà lo stesso risultato di jQuery.type()

8
Yukulélé

Puoi applicare Object.prototype.toString a qualsiasi oggetto:

var toString = Object.prototype.toString;

console.log(toString.call([]));
//-> [object Array]

console.log(toString.call(/reg/g));
//-> [object RegExp]

console.log(toString.call({}));
//-> [object Object]

Funziona bene su tutti i browser, con l'eccezione di IE - quando si chiama questo su una variabile ottenuta da un'altra finestra si sputerà solo [object Object].

3
Andy E

My 2 ¢! In realtà, parte del motivo per cui sto lanciando questo qui, nonostante la lunga lista di risposte, è di fornire un po 'di più all in one tipo di soluzione e riprendi qualche feed in futuro su come espanderlo per includerne di più real types.

Con la seguente soluzione, come sopra menzionato, ho combinato un paio di soluzioni trovate qui, oltre a incorporare una correzione per restituire un valore di jQuery su oggetto definito jQuery se disponibile . Aggiungo anche il metodo al prototipo Object nativo. So che è spesso tabù, in quanto potrebbe interferire con altre estensioni di questo tipo, ma lo lascio a user beware. Se non ti piace questo modo di farlo, copia semplicemente la funzione di base ovunque tu voglia e sostituisci tutte le variabili di this con un parametro argomento da passare (come argomenti [0]).

;(function() {  //  Object.realType
    function realType(toLower) {
        var r = typeof this;
        try {
            if (window.hasOwnProperty('jQuery') && this.constructor && this.constructor == jQuery) r = 'jQuery';
            else r = this.constructor && this.constructor.name ? this.constructor.name : Object.prototype.toString.call(this).slice(8, -1);
        }
        catch(e) { if (this['toString']) r = this.toString().slice(8, -1); }
        return !toLower ? r : r.toLowerCase();
    }
    Object['defineProperty'] && !Object.prototype.hasOwnProperty('realType')
        ? Object.defineProperty(Object.prototype, 'realType', { value: realType }) : Object.prototype['realType'] = realType;
})();

Quindi usa semplicemente con facilità, in questo modo:

obj.realType()  //  would return 'Object'
obj.realType(true)  //  would return 'object'

Nota: Esiste 1 argomento passabile. Se è bool di true, il ritorno sarà sempre in in minuscolo .

Altri esempi:

true.realType();                            //  "Boolean"
var a = 4; a.realType();                    //  "Number"
$('div:first').realType();                   // "jQuery"
document.createElement('div').realType()    //  "HTMLDivElement"

Se hai qualcosa da aggiungere che potrebbe essere utile, ad esempio definire quando un oggetto è stato creato con un'altra libreria (Moo, Proto, Yui, Dojo, ecc.), Non esitare a commentare o modificare questo e far sì che diventi più preciso e preciso OR passa sopra a GitHub Ho fatto per questo e fammi sapere. Troverai anche un link rapido a un file cdn min lì.

3
SpYk3HH
function getType(obj) {
    if(obj && obj.constructor && obj.constructor.name) {
        return obj.constructor.name;
    }
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

Nei miei test preliminari, funziona abbastanza bene. Il primo caso stamperà il nome di qualsiasi oggetto creato con "nuovo" e il secondo caso catturerà tutto il resto.

Sto usando (8, -1) perché presumo che il risultato inizi sempre con [object e finisca con ] ma non sono sicuro che sia vero in ogni scenario.

2
mpen