Ottieni il nome del tipo di un oggetto


1193

Esiste un JavaScript equivalente di Java s' class.getName()?


Questa domanda presuppone che sappiamo cosa fa Java class.getName (). Dal momento che non lo so, non sono sicuro che le risposte mi possano aiutare.
user34660,

2
@ user34660 Penso che possiamo tranquillamente supporre che ciò che fa è ottenere il nome del tipo di un oggetto.
Stack Underflow

1
@StackUnderflow: Tranne, in realtà no. Ottiene il nome della classe di un oggetto , che non è lo stesso del tipo di un oggetto .
Jörg W Mittag,

1
@ JörgWMittag Ah sì, certo. Vedi cosa succede quando vai in giro assumendo le cose in sicurezza?
Stack Underflow

Risposte:


1540

Esiste un equivalente JavaScript di Java class.getName()?

No .

Aggiornamento ES2015 : il nome di class Foo {}èFoo.name . Il nome della thingclasse, indipendentemente dal thingtipo, è thing.constructor.name. I costruttori incorporati in un ambiente ES2015 hanno la nameproprietà corretta ; per esempio (2).constructor.nameè "Number".


Ma qui ci sono vari hack che cadono tutti in un modo o nell'altro:

Ecco un hack che farà ciò di cui hai bisogno: tieni presente che modifica il prototipo dell'Oggetto, qualcosa che la gente non vede bene (di solito per una buona ragione)

Object.prototype.getName = function() { 
   var funcNameRegex = /function (.{1,})\(/;
   var results = (funcNameRegex).exec((this).constructor.toString());
   return (results && results.length > 1) ? results[1] : "";
};

Ora, tutti i tuoi oggetti avranno la funzione getName(), che restituirà il nome del costruttore come una stringa. Ho provato questo FF3e IE7, non posso parlare per altre implementazioni.

Se non vuoi farlo, ecco una discussione sui vari modi di determinare i tipi in JavaScript ...


Recentemente ho aggiornato questo per essere un po 'più esaustivo, anche se non è così. Correzioni benvenute ...

Utilizzo della constructorproprietà ...

Ognuno objectha un valore per la sua constructorproprietà, ma a seconda di come è objectstato costruito e di ciò che vuoi fare con quel valore, potrebbe essere utile o meno.

In generale, è possibile utilizzare la constructorproprietà per testare il tipo di oggetto in questo modo:

var myArray = [1,2,3];
(myArray.constructor == Array); // true

Quindi, funziona abbastanza bene per la maggior parte delle esigenze. Detto ciò...

Avvertenze

Non funziona AFFATTO in molti casi

Questo modello, sebbene rotto, è abbastanza comune:

function Thingy() {
}
Thingy.prototype = {
    method1: function() {
    },
    method2: function() {
    }
};

Objectscostruito via new Thingyavrà una constructorproprietà che punta a Objectno Thingy. Quindi cadiamo proprio all'inizio; semplicemente non puoi fidarti constructordi una base di codice che non controlli.

Ereditarietà multipla

Un esempio in cui non è così ovvio è l'utilizzo dell'ereditarietà multipla:

function a() { this.foo = 1;}
function b() { this.bar = 2; }
b.prototype = new a(); // b inherits from a

Le cose ora non funzionano come ci si potrebbe aspettare che:

var f = new b(); // instantiate a new object with the b constructor
(f.constructor == b); // false
(f.constructor == a); // true

Quindi, potresti ottenere risultati imprevisti se il objecttuo test ha un objectset diverso come suo prototype. Ci sono modi per aggirare questo al di fuori dell'ambito di questa discussione.

Ci sono altri usi per la constructorproprietà, alcuni interessanti, altri meno; per ora non approfondiremo questi usi poiché non è rilevante per questa discussione.

Non funzionerà cross-frame e cross-window

L'uso .constructorper il controllo del tipo si interromperà quando si desidera controllare il tipo di oggetti provenienti da windowoggetti diversi , ad esempio quello di un iframe o di una finestra popup. Questo perché esiste una versione diversa di ciascun tipo di core constructorin ciascuna `finestra ', cioè

iframe.contentWindow.Array === Array // false

Utilizzo instanceofdell'operatore ...

L' instanceofoperatore è anche un modo pulito di testare il objecttipo, ma ha i suoi potenziali problemi, proprio come la constructorproprietà.

var myArray = [1,2,3];
(myArray instanceof Array); // true
(myArray instanceof Object); // true

Ma instanceofnon funziona per valori letterali (perché i letterali non lo sono Objects)

3 instanceof Number // false
'abc' instanceof String // false
true instanceof Boolean // false

I letterali devono essere racchiusi in un Objectper instanceofpoter funzionare, ad esempio

new Number(3) instanceof Number // true

Il .constructorcontrollo funziona bene per i letterali perché l' .invocazione del metodo avvolge implicitamente i letterali nel rispettivo tipo di oggetto

3..constructor === Number // true
'abc'.constructor === String // true
true.constructor === Boolean // true

Perché due punti per il 3? Perché Javascript interpreta il primo punto come un punto decimale;)

Non funzionerà cross-frame e cross-window

instanceofinoltre non funzionerà su finestre diverse, per lo stesso motivo del constructorcontrollo delle proprietà.


Utilizzo della nameproprietà della constructorproprietà ...

Non funziona AFFATTO in molti casi

Ancora una volta, vedi sopra; è abbastanza comune constructoressere completamente, completamente sbagliato e inutile.

NON funziona in <IE9

L'uso di myObjectInstance.constructor.namefornisce una stringa contenente il nome della constructorfunzione utilizzata, ma è soggetto alle avvertenze sulla constructorproprietà menzionate in precedenza.

Per IE9 e versioni successive, è possibile applicare la patch scimmia nel supporto :

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var funcNameRegex = /function\s+([^\s(]+)\s*\(/;
            var results = (funcNameRegex).exec((this).toString());
            return (results && results.length > 1) ? results[1] : "";
        },
        set: function(value) {}
    });
}

Versione aggiornata dall'articolo in questione. Questo è stato aggiunto 3 mesi dopo la pubblicazione dell'articolo, questa è la versione consigliata da usare dall'autore dell'articolo Matthew Scharley. Questa modifica è stata ispirata da commenti che evidenziano potenziali insidie nel codice precedente.

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var funcNameRegex = /function\s([^(]{1,})\(/;
            var results = (funcNameRegex).exec((this).toString());
            return (results && results.length > 1) ? results[1].trim() : "";
        },
        set: function(value) {}
    });
}

Utilizzo di Object.prototype.toString

Si scopre che, come indicato in questo post , è possibile utilizzare Object.prototype.toString- l'implementazione generica e di basso livello toString- per ottenere il tipo per tutti i tipi predefiniti

Object.prototype.toString.call('abc') // [object String]
Object.prototype.toString.call(/abc/) // [object RegExp]
Object.prototype.toString.call([1,2,3]) // [object Array]

Si potrebbe scrivere una funzione di supporto breve come

function type(obj){
    return Object.prototype.toString.call(obj).slice(8, -1);
}

per rimuovere la cruft e ottenere solo il nome del tipo

type('abc') // String

Tuttavia, verrà restituito Objectper tutti i tipi definiti dall'utente.


Avvertenze per tutti ...

Tutti questi sono soggetti a un potenziale problema, e questa è la domanda su come è stato costruito l'oggetto in questione. Ecco vari modi di costruire oggetti e i valori restituiti dai diversi metodi di verifica del tipo:

// using a named function:
function Foo() { this.a = 1; }
var obj = new Foo();
(obj instanceof Object);          // true
(obj instanceof Foo);             // true
(obj.constructor == Foo);         // true
(obj.constructor.name == "Foo");  // true

// let's add some prototypical inheritance
function Bar() { this.b = 2; }
Foo.prototype = new Bar();
obj = new Foo();
(obj instanceof Object);          // true
(obj instanceof Foo);             // true
(obj.constructor == Foo);         // false
(obj.constructor.name == "Foo");  // false


// using an anonymous function:
obj = new (function() { this.a = 1; })();
(obj instanceof Object);              // true
(obj.constructor == obj.constructor); // true
(obj.constructor.name == "");         // true


// using an anonymous function assigned to a variable
var Foo = function() { this.a = 1; };
obj = new Foo();
(obj instanceof Object);      // true
(obj instanceof Foo);         // true
(obj.constructor == Foo);     // true
(obj.constructor.name == ""); // true


// using object literal syntax
obj = { foo : 1 };
(obj instanceof Object);            // true
(obj.constructor == Object);        // true
(obj.constructor.name == "Object"); // true

Sebbene non tutte le permutazioni siano presenti in questo set di esempi, speriamo che ce ne siano abbastanza per darti un'idea di come le cose disordinate potrebbero arrivare a seconda delle tue esigenze. Non dare per scontato nulla, se non capisci esattamente cosa stai cercando, potresti finire con la rottura del codice dove non ti aspetti a causa della mancanza di grokking delle sottigliezze.

NOTA:

La discussione typeofsull'operatore può sembrare un'omissione lampante, ma in realtà non è utile per aiutare a identificare se si objecttratta di un determinato tipo, poiché è molto semplicistico. Capire dove typeofè utile è importante, ma al momento non ritengo che sia estremamente rilevante per questa discussione. La mia mente è aperta al cambiamento però. :)


58
Beh, ho pensato che potrei anche farlo - il punto di Stack Overflow è essere un po 'come un wiki, e questo è molto più in linea con quell'intento, credo. Indipendentemente da ciò, volevo solo essere un po 'approfondito.
Jason Bunting,

Reiterando una risposta di seguito --- la tua estensione al prototipo Object non funziona in IE8 - qualcuno sa cosa funzionerebbe in IE8?
Adam,

5
Funzionerà se lo fai come questa funzione a () {this.a = 1;} funzione b () {this.b = 2; } b.prototype = new a (); // b eredita da a b.prototype.constructor = b; // Modo corretto di eredità prototipica var f = new b (); // crea un nuovo oggetto con il costruttore b (f.constructor == b); // TRUE (f.constructor == a); // FALSO
Boris Hamanov,

9
Ora, ecco come dovrebbe essere la maggior parte delle risposte su StackOverflow. (non prendere la lunghezza della risposta come parametro determinante, ma la completezza)
kumarharsh

44
È importante notare che qualsiasi tecnica che controlla il constructormetodo dell'oggetto (con .toString()o .name) non funzionerà se il tuo Javascript è stato minimizzato con uno strumento come uglify o la pipeline delle risorse di Rails. La minificazione rinomina il costruttore, quindi finirai con nomi di classe errati come n. Se ti trovi in ​​questo scenario, potresti voler definire manualmente una classNameproprietà sui tuoi oggetti e usarla invece.
Gabe Martin-Dempesy,

126

La risposta di Jason Bunting mi ha dato abbastanza indizio per trovare ciò di cui avevo bisogno:

<<Object instance>>.constructor.name

Quindi, ad esempio, nel seguente codice:

function MyObject() {}
var myInstance = new MyObject();

myInstance.constructor.namesarebbe tornato "MyObject".


22
Per completezza, vale la pena ricordare che l'utilizzo di constructor.name funziona solo se è stata utilizzata una funzione denominata come costruttore anziché una funzione anonima assegnata a una variabile.
Matthew Crumley,

20
Per completezza, vale la pena ricordare che non funziona nei browser IE --- non supportano l'attributo "name" nelle funzioni.
Eugene Lazutkin,

2
@Eugene - Me ne sono dimenticato ... Immagino di aver passato troppo tempo a fare javascript fuori dai browser.
Matthew Crumley,

2
function getType(o) { return o && o.constructor && o.constructor.name }
justin.m.chase

Questo è così completo.
ibico,

26

Un piccolo trucco che uso:

function Square(){
    this.className = "Square";
    this.corners = 4;
}

var MySquare = new Square();
console.log(MySquare.className); // "Square"

11
Non mi piace particolarmente. È più una specie di trucco sporco. D'altra parte, se non hai troppi costruttori, potrebbe funzionare bene.
pimvdb,

13
@pimvdb: penso che sia più pulito della modifica del prototipo dell'oggetto, come la risposta accettata.
Daniel Szabo,

4
@DanielSzabo se una proprietà deve avere lo stesso valore tra tutte le istanze di un prototipo, preferisco decisamente metterla sul prototipo: metterla su ogni istanza è super ridondante e i metadati mancano dal prototipo stesso. Detto questo, la soluzione più saggia è stata adottata in ES6: se hai class Square, il nome è Square.name/ MySquare.constructor.namepiuttosto che Square.prototype.name; attivando namela funzione di costruzione non inquina il prototipo o alcuna istanza, ma è accessibile da entrambi.
Andy,

17

Aggiornare

Per essere precisi, penso che OP abbia richiesto una funzione che recupera il nome del costruttore per un particolare oggetto. In termini di Javascript, objectnon ha un tipo ma è un tipo e in sé . Tuttavia, oggetti diversi possono avere costruttori diversi .

Object.prototype.getConstructorName = function () {
   var str = (this.prototype ? this.prototype.constructor : this.constructor).toString();
   var cname = str.match(/function\s(\w*)/)[1];
   var aliases = ["", "anonymous", "Anonymous"];
   return aliases.indexOf(cname) > -1 ? "Function" : cname;
}

new Array().getConstructorName();  // returns "Array"
(function () {})().getConstructorName(); // returns "Function"

 


Nota: l'esempio seguente è obsoleto.

Un post sul blog collegato da Christian Sciberras contiene un buon esempio su come farlo. Vale a dire, estendendo il prototipo Object:

if (!Object.prototype.getClassName) {
    Object.prototype.getClassName = function () {
        return Object.prototype.toString.call(this).match(/^\[object\s(.*)\]$/)[1];
    }
}

var test = [1,2,3,4,5];

alert(test.getClassName()); // returns Array

2
Bello, ma stiamo di nuovo nominando: JS non ha lezioni.
mikemaccana,

@nailer - Consiglio di utilizzare la funzione aggiornata, quella precedente viene conservata per motivi puramente storici.
Saul,

Funziona ma va notato che potrebbe essere fatto senza modificare Object.prototype, creando una funzione che prende l'oggetto come primo argomento e lo utilizza invece di "questo" all'interno della funzione.
Matt Browne,

2
@Matt - Sicuro. E 'solo che avere un metodo di oggetto è più concisa: test.getClassName()vs getClassName.apply(test).
Saul,

12

Utilizzo di Object.prototype.toString

Si scopre che, come indicato in questo post, è possibile utilizzare Object.prototype.toString - l'implementazione generica di basso livello di toString - per ottenere il tipo per tutti i tipi predefiniti

Object.prototype.toString.call('abc') // [object String]
Object.prototype.toString.call(/abc/) // [object RegExp]
Object.prototype.toString.call([1,2,3]) // [object Array]

Si potrebbe scrivere una funzione di supporto breve come

function type(obj){
    return Object.prototype.toString.call(obj]).match(/\s\w+/)[0].trim()
}

return [object String] as String
return [object Number] as Number
return [object Object] as Object
return [object Undefined] as Undefined
return [object Function] as Function

6
Non è necessario utilizzare regex per analizzare il nome dell'oggetto. Basta usare .slice():Object.prototype.toString.call(obj).slice( 8, -1 );
bobobobo il

9

Ecco una soluzione che ho trovato che risolve i difetti di esempio di. Può controllare i tipi di un oggetto da finestre incrociate e cornici incrociate e non ha problemi con i tipi primitivi.

function getType(o) {
    return Object.prototype.toString.call(o).match(/^\[object\s(.*)\]$/)[1];
}
function isInstance(obj, type) {
    var ret = false,
    isTypeAString = getType(type) == "String",
    functionConstructor, i, l, typeArray, context;
    if (!isTypeAString && getType(type) != "Function") {
        throw new TypeError("type argument must be a string or function");
    }
    if (obj !== undefined && obj !== null && obj.constructor) {
        //get the Function constructor
        functionConstructor = obj.constructor;
        while (functionConstructor != functionConstructor.constructor) {
            functionConstructor = functionConstructor.constructor;
        }
        //get the object's window
        context = functionConstructor == Function ? self : functionConstructor("return window")();
        //get the constructor for the type
        if (isTypeAString) {
            //type is a string so we'll build the context (window.Array or window.some.Type)
            for (typeArray = type.split("."), i = 0, l = typeArray.length; i < l && context; i++) {
                context = context[typeArray[i]];
            }
        } else {
            //type is a function so execute the function passing in the object's window
            //the return should be a constructor
            context = type(context);
        }
        //check if the object is an instance of the constructor
        if (context) {
            ret = obj instanceof context;
            if (!ret && (type == "Number" || type == "String" || type == "Boolean")) {
                ret = obj.constructor == context
            }
        }
    }
    return ret;
}

isInstance richiede due parametri: un oggetto e un tipo. Il vero trucco di come funziona è che controlla se l'oggetto proviene dalla stessa finestra e se non ottiene la finestra dell'oggetto.

Esempi:

isInstance([], "Array"); //true
isInstance("some string", "String"); //true
isInstance(new Object(), "Object"); //true

function Animal() {}
function Dog() {}
Dog.prototype = new Animal();

isInstance(new Dog(), "Dog"); //true
isInstance(new Dog(), "Animal"); //true
isInstance(new Dog(), "Object"); //true
isInstance(new Animal(), "Dog"); //false

L'argomento type può anche essere una funzione di callback che restituisce un costruttore. La funzione di callback riceverà un parametro che è la finestra dell'oggetto fornito.

Esempi:

//"Arguments" type check
var args = (function() {
    return arguments;
}());

isInstance(args, function(w) {
    return w.Function("return arguments.constructor")();
}); //true

//"NodeList" type check
var nl = document.getElementsByTagName("*");

isInstance(nl, function(w) {
    return w.document.getElementsByTagName("bs").constructor;
}); //true

Una cosa da tenere a mente è che IE <9 non fornisce il costruttore su tutti gli oggetti, quindi il test sopra riportato per NodeList restituisce false e anche un isInstance (alert, "Function") restituisce false.


8

In realtà stavo cercando una cosa simile e mi sono imbattuto in questa domanda. Ecco come ottengo i tipi: jsfiddle

var TypeOf = function ( thing ) {

    var typeOfThing = typeof thing;

    if ( 'object' === typeOfThing ) {

        typeOfThing = Object.prototype.toString.call( thing );

        if ( '[object Object]' === typeOfThing ) {

            if ( thing.constructor.name ) {
                return thing.constructor.name;
            } 

            else if ( '[' === thing.constructor.toString().charAt(0) ) {
                typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );
            } 

            else {

                typeOfThing = thing.constructor.toString().match( /function\s*(\w+)/ );

                if ( typeOfThing ) { 
                    return typeOfThing[1];
                } 

                else {
                    return 'Function';
                }
            }
        } 

        else {
            typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );
        }
    }

    return typeOfThing.charAt(0).toUpperCase() + typeOfThing.slice(1);
}

7

Dovresti usare somevar.constructor.namecome un:

    
    const getVariableType = a => a.constructor.name.toLowerCase();

    const d = new Date();
    const res1 = getVariableType(d); // 'date'
    const num = 5;
    const res2 = getVariableType(num); // 'number'
    const fn = () => {};
    const res3 = getVariableType(fn); // 'function'

    console.log(res1); // 'date'
    console.log(res2); // 'number'
    console.log(res3); // 'function'


6

Usa constructor.namequando puoi, e regex quando non posso.

Function.prototype.getName = function(){
  if (typeof this.name != 'undefined')
    return this.name;
  else
    return /function (.+)\(/.exec(this.toString())[1];
};

6

La funzione kind () di Agave.JS restituirà:

  • il prototipo più vicino nell'albero ereditario
  • per tipi sempre primitivi come 'null' e 'undefined', il nome primitivo.

Funziona su tutti gli oggetti e le primitive JS, indipendentemente da come sono stati creati e non ha sorprese. Esempi:

Numeri

kind(37) === 'Number'
kind(3.14) === 'Number'
kind(Math.LN2) === 'Number'
kind(Infinity) === 'Number'
kind(Number(1)) === 'Number'
kind(new Number(1)) === 'Number'

NaN

kind(NaN) === 'NaN'

stringhe

kind('') === 'String'
kind('bla') === 'String'
kind(String("abc")) === 'String'
kind(new String("abc")) === 'String'

booleani

kind(true) === 'Boolean'
kind(false) === 'Boolean'
kind(new Boolean(true)) === 'Boolean'

Array

kind([1, 2, 4]) === 'Array'
kind(new Array(1, 2, 3)) === 'Array'

Oggetti

kind({a:1}) === 'Object'
kind(new Object()) === 'Object'

Date

kind(new Date()) === 'Date'

funzioni

kind(function(){}) === 'Function'
kind(new Function("console.log(arguments)")) === 'Function'
kind(Math.sin) === 'Function'

non definito

kind(undefined) === 'undefined'

nullo

kind(null) === 'null'

5

Puoi usare l' instanceofoperatore per vedere se un oggetto è un'istanza di un'altra, ma poiché non ci sono classi, non puoi ottenere un nome di classe.


Mentre è vero che JavaScript non ha classi come costrutto di linguaggio, la convenzione generica è comunque che un tipo di oggetto è chiamato una classe ..
Saul

2
@greg Sicuro, ma instanceofcontrolla solo se un oggetto eredita da un altro oggetto. Ad esempio, un semplice []eredita da Array, ma Array eredita anche da Object. Poiché la maggior parte degli oggetti ha più livelli di ereditarietà, trovare il prototipo più vicino è una tecnica migliore. Vedi la mia risposta per come.
mikemaccana,

4

Ecco un'implementazione basata sulla risposta accettata :

/**
 * Returns the name of an object's type.
 *
 * If the input is undefined, returns "Undefined".
 * If the input is null, returns "Null".
 * If the input is a boolean, returns "Boolean".
 * If the input is a number, returns "Number".
 * If the input is a string, returns "String".
 * If the input is a named function or a class constructor, returns "Function".
 * If the input is an anonymous function, returns "AnonymousFunction".
 * If the input is an arrow function, returns "ArrowFunction".
 * If the input is a class instance, returns "Object".
 *
 * @param {Object} object an object
 * @return {String} the name of the object's class
 * @see <a href="https://stackoverflow.com/a/332429/14731">https://stackoverflow.com/a/332429/14731</a>
 * @see getFunctionName
 * @see getObjectClass 
 */
function getTypeName(object)
{
  const objectToString = Object.prototype.toString.call(object).slice(8, -1);
  if (objectToString === "Function")
  {
    const instanceToString = object.toString();
    if (instanceToString.indexOf(" => ") != -1)
      return "ArrowFunction";
    const getFunctionName = /^function ([^(]+)\(/;
    const match = instanceToString.match(getFunctionName);
    if (match === null)
      return "AnonymousFunction";
    return "Function";
  }
  // Built-in types (e.g. String) or class instances
  return objectToString;
};

/**
 * Returns the name of a function.
 *
 * If the input is an anonymous function, returns "".
 * If the input is an arrow function, returns "=>".
 *
 * @param {Function} fn a function
 * @return {String} the name of the function
 * @throws {TypeError} if {@code fn} is not a function
 * @see getTypeName
 */
function getFunctionName(fn)
{
  try
  {
    const instanceToString = fn.toString();
    if (instanceToString.indexOf(" => ") != -1)
      return "=>";
    const getFunctionName = /^function ([^(]+)\(/;
    const match = instanceToString.match(getFunctionName);
    if (match === null)
    {
      const objectToString = Object.prototype.toString.call(fn).slice(8, -1);
      if (objectToString === "Function")
        return "";
      throw TypeError("object must be a Function.\n" +
        "Actual: " + getTypeName(fn));
    }
    return match[1];
  }
  catch (e)
  {
    throw TypeError("object must be a Function.\n" +
      "Actual: " + getTypeName(fn));
  }
};

/**
 * @param {Object} object an object
 * @return {String} the name of the object's class
 * @throws {TypeError} if {@code object} is not an Object
 * @see getTypeName
 */
function getObjectClass(object)
{
  const getFunctionName = /^function ([^(]+)\(/;
  const result = object.constructor.toString().match(getFunctionName)[1];
  if (result === "Function")
  {
    throw TypeError("object must be an Object.\n" +
      "Actual: " + getTypeName(object));
  }
  return result;
};


function UserFunction()
{
}

function UserClass()
{
}

let anonymousFunction = function()
{
};

let arrowFunction = i => i + 1;

console.log("getTypeName(undefined): " + getTypeName(undefined));
console.log("getTypeName(null): " + getTypeName(null));
console.log("getTypeName(true): " + getTypeName(true));
console.log("getTypeName(5): " + getTypeName(5));
console.log("getTypeName(\"text\"): " + getTypeName("text"));
console.log("getTypeName(userFunction): " + getTypeName(UserFunction));
console.log("getFunctionName(userFunction): " + getFunctionName(UserFunction));
console.log("getTypeName(anonymousFunction): " + getTypeName(anonymousFunction));
console.log("getFunctionName(anonymousFunction): " + getFunctionName(anonymousFunction));
console.log("getTypeName(arrowFunction): " + getTypeName(arrowFunction));
console.log("getFunctionName(arrowFunction): " + getFunctionName(arrowFunction));
//console.log("getFunctionName(userClass): " + getFunctionName(new UserClass()));
console.log("getTypeName(userClass): " + getTypeName(new UserClass()));
console.log("getObjectClass(userClass): " + getObjectClass(new UserClass()));
//console.log("getObjectClass(userFunction): " + getObjectClass(UserFunction));
//console.log("getObjectClass(userFunction): " + getObjectClass(anonymousFunction));
//console.log("getObjectClass(arrowFunction): " + getObjectClass(arrowFunction));
console.log("getTypeName(nativeObject): " + getTypeName(navigator.mediaDevices.getUserMedia));
console.log("getFunctionName(nativeObject): " + getFunctionName(navigator.mediaDevices.getUserMedia));

Usiamo la proprietà del costruttore solo quando non abbiamo altra scelta.


3

È possibile utilizzare l'operatore "instanceof" per determinare se un oggetto è un'istanza di una determinata classe o meno. Se non si conosce il nome del tipo di un oggetto, è possibile utilizzare la sua proprietà di costruzione. La proprietà costruttore degli oggetti è un riferimento alla funzione utilizzata per inizializzarli. Esempio:

function Circle (x,y,radius) {
    this._x = x;
    this._y = y;
    this._radius = raduius;
}
var c1 = new Circle(10,20,5);

Ora c1.constructor è un riferimento alla Circle()funzione. Puoi anche usare l' typeofoperatore, ma l' typeofoperatore mostra informazioni limitate. Una soluzione è utilizzare il toString()metodo dell'oggetto globale Object. Ad esempio, se si dispone di un oggetto, ad esempio myObject, è possibile utilizzare il toString()metodo dell'oggetto globale per determinare il tipo della classe di myObject. Usa questo:

Object.prototype.toString.apply(myObject);

3

Di 'che hai var obj;

Se vuoi solo il nome del tipo di obj, come "Object", "Array" o "String", puoi usare questo:

Object.prototype.toString.call(obj).split(' ')[1].replace(']', '');

2

Il più vicino che puoi ottenere è typeof, ma restituisce solo "oggetto" per qualsiasi tipo di tipo personalizzato. Per quelli, vedi Jason Bunting .

Modifica, Jason ha cancellato il suo post per qualche motivo, quindi usa la constructorproprietà di Object .


Sì, scusa, l'ho cancellato perché immaginavo che instanceof () fosse un modo migliore per fare le cose, ma l'ho semplicemente cancellato in modo che potesse fungere da riferimento.
Jason Bunting,

2
Le risposte tutt'altro che perfette sono ancora utili, anche se solo agli altri per venire alla domanda in seguito perché hanno un problema simile. Quindi non dovresti davvero eliminarli. Salva le eliminazioni per le risposte errate.
sblundy,

2
Sì, lo so - stai predicando al coro, ho detto la stessa cosa agli altri. Vivere quelle cose che sappiamo essere vere è spesso più difficile di quanto sembri. :)
Jason Bunting,

0

Se qualcuno stava cercando una soluzione che funzioni con jQuery, ecco il codice wiki modificato (l'originale interrompe jQuery).

Object.defineProperty(Object.prototype, "getClassName", {
    value: function() {
        var funcNameRegex = /function (.{1,})\(/;
        var results = (funcNameRegex).exec((this).constructor.toString());
        return (results && results.length > 1) ? results[1] : "";
    }
});

Sì, jQuery non riesce a fare un controllo 'hasOwnProperty' e quindi elenca getNamee cade.
nicodemus13,

0

Lodash ha molti isMethods, quindi se stai usando Lodash forse un mixin come questo può essere utile:

  // Mixin for identifying a Javascript Object

  _.mixin({
      'identify' : function(object) {
        var output;
          var isMethods = ['isArguments', 'isArray', 'isArguments', 'isBoolean', 'isDate', 'isArguments', 
              'isElement', 'isError', 'isFunction', 'isNaN', 'isNull', 'isNumber', 
              'isPlainObject', 'isRegExp', 'isString', 'isTypedArray', 'isUndefined', 'isEmpty', 'isObject']

          this.each(isMethods, function (method) {
              if (this[method](object)) {
                output = method;
                return false;
              }
          }.bind(this));
      return output;
      }
  });

Aggiunge un metodo a lodash chiamato "identifica" che funziona come segue:

console.log(_.identify('hello friend'));       // isString

Plunker: http://plnkr.co/edit/Zdr0KDtQt76Ul3KTEDSN


0

Ok, gente, sto lentamente costruendo un metodo tutto per questo da qualche anno lol! Il trucco è:

  1. Avere un meccanismo per la creazione di classi.
  2. Dispone di un meccanismo per controllare tutte le classi, le primitive e i valori creati dall'utente creati / generati dai costruttori nativi.
  3. Avere un meccanismo per estendere le classi create dall'utente in nuove in modo che la funzionalità di cui sopra permea attraverso il tuo codice / applicazione / libreria / ecc.

Per un esempio (o per vedere come ho affrontato il problema) guarda il seguente codice su github: https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js e cerca:

classOf =, classOfIs =e o defineSubClass =(senza i backtick (`)).

Come puoi vedere, ho alcuni meccanismi per forzarmi classOfa darmi sempre il nome del tipo di classe / costruttore, indipendentemente dal fatto che sia una classe primitiva, una definita dall'utente, un valore creato usando un costruttore nativo, Null, NaN, ecc. Per ogni singolo valore JavaScript otterrò il nome univoco dalla classOffunzione. Inoltre, posso passare a costruttori reali sjl.classOfIsper controllare il tipo di un valore oltre a poter passare anche il nome del suo tipo! Quindi per esempio:

`` // Per favore, perdona gli spazi dei nomi lunghi! Non avevo idea dell'impatto fino a dopo averli usati per un po '(fanno schifo ahah)

var SomeCustomClass = sjl.package.stdlib.Extendable.extend({
    constructor: function SomeCustomClass () {},
    // ...
}),

HelloIterator = sjl.ns.stdlib.Iterator.extend( 
    function HelloIterator () {}, 
    { /* ... methods here ... */ },
    { /* ... static props/methods here ... */ }
),

helloIt = new HelloIterator();

sjl.classOfIs(new SomeCustomClass(), SomeCustomClass) === true; // `true`
sjl.classOfIs(helloIt, HelloIterator) === true; // `true`

var someString = 'helloworld';

sjl.classOfIs(someString, String) === true; // `true`

sjl.classOfIs(99, Number) === true; // true

sjl.classOf(NaN) === 'NaN'; // true

sjl.classOf(new Map()) === 'Map';
sjl.classOf(new Set()) === 'Set';
sjl.classOfIs([1, 2, 4], Array) === true; // `true`

// etc..

// Also optionally the type you want to check against could be the type's name
sjl.classOfIs(['a', 'b', 'c'], 'Array') === true; // `true`!
sjl.classOfIs(helloIt, 'HelloIterator') === true; // `true`!

`` `

Se sei interessato a leggere di più su come utilizzo la configurazione di cui sopra dai un'occhiata al repository: https://github.com/elycruz/sjljs

Libri anche con contenuti sull'argomento: - "JavaScript Patterns" di Stoyan Stefanov. - "Javascript - La guida definitiva". di David Flanagan. - e molti altri .. (cerca nel web).

Inoltre puoi testare rapidamente le funzionalità di cui sto parlando qui: - http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (anche il percorso 0.5.18 nell'URL ha le fonti da github lì meno il nodo_moduli e simili).

Buona programmazione!


0

Abbastanza semplice!

  • Il mio metodo preferito per ottenere il tipo di qualsiasi cosa in JS
function getType(entity){
    var x = Object.prototype.toString.call(entity)
    return x.split(" ")[1].split(']')[0].toLowerCase()
}
  • il mio metodo preferito per controllare il tipo di qualsiasi cosa in JS
function checkType(entity, type){
    return getType(entity) === type
}

-1

Usa class.name. Questo funziona anche con function.name.

class TestA {}
console.log(TestA.name); // "TestA"

function TestB() {}
console.log(TestB.name); // "TestB"

La domanda dice chiaramente classe non istanza.
qwertzguy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.