Come ottenere la classe di un oggetto JavaScript?


728

Ho creato un oggetto JavaScript, ma come posso determinare la classe di quell'oggetto?

Voglio qualcosa di simile al .getClass()metodo Java .


6
per esempio, creo una persona come questa: var p = new Person (); Ho un oggetto persona che ha chiamato "p", come posso usare "p" per recuperare il nome della classe: "persona".
DNB5:


Aggiornamento: A partire da ECMAScript 6, JavaScript non ha ancora un classtipo. Esso ha una classparola chiave e classla sintassi per la creazione di prototipi in cui i metodi possono più facilmente accesso super.
james_womack

Che dire di Object.className?
Paul Basenko,

@ Paul-Basenko: "className" non ti dirà la classe dell'oggetto, ma restituirà il contenuto della proprietà "class" di un elemento HTML, che si riferisce alle classi CSS. Volete anche usare "classList" per gestirli facilmente, ma non è correlato alla domanda del PO.
Obsidian

Risposte:


1010

Non esiste una controparte esatta di Java getClass()in JavaScript. Principalmente ciò è dovuto al fatto che JavaScript è un linguaggio basato sui prototipi , al contrario di Java che è un linguaggio di classe .

A seconda di ciò di cui hai bisogno getClass(), ci sono diverse opzioni in JavaScript:

Alcuni esempi:

function Foo() {}
var foo = new Foo();

typeof Foo;             // == "function"
typeof foo;             // == "object"

foo instanceof Foo;     // == true
foo.constructor.name;   // == "Foo"
Foo.name                // == "Foo"    

Foo.prototype.isPrototypeOf(foo);   // == true

Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21);            // == 42

Nota: se stai compilando il tuo codice con Uglify, cambierà i nomi delle classi non globali. Per evitare ciò, Uglify ha un --mangleparametro che puoi impostare su false usando gulp o grunt .


6
Probabilmente dovrebbe essere func.prototype(sì, le funzioni sono oggetti, ma la prototypeproprietà è rilevante solo sugli oggetti funzione).
Miglia,

5
potresti anche voler menzionare instanceof/ isPrototypeOf()e il non standard__proto__
Christoph

9
ES5 ha adizionaleObject.getPrototypeOf()
Christoph

22
Attenzione : non fare affidamento su constructor.namese il codice viene minimizzato. Il nome della funzione cambierà arbitrariamente.
igorsantos07

3
@ igorsantos07, almeno nel 2019; i primi 5-10 risultati di google per "minifier javascript online" riconoscono construction.namecome token da ignorare / non minimizzare. Oltre alla maggior parte (se non a tutti) il software minificatore fornisce regole di eccezione.
corvo vulcanico,

297
obj.constructor.name

è un metodo affidabile nei browser moderni. Function.nameè stato ufficialmente aggiunto allo standard in ES6, rendendolo un mezzo conforme agli standard per ottenere la "classe" di un oggetto JavaScript come stringa. Se l'oggetto viene istanziato con var obj = new MyClass(), restituirà "MyClass".

Restituirà "Numero" per i numeri, "Matrice" per le matrici e "Funzione" per le funzioni, ecc. In genere si comporta come previsto. Gli unici casi in cui fallisce sono se un oggetto viene creato senza un prototipo, via Object.create( null )o se l'oggetto è stato istanziato da una funzione anonima (senza nome).

Nota anche che se stai minimizzando il tuo codice, non è sicuro fare un confronto con stringhe di tipo hardcoded. Ad esempio invece di controllare se obj.constructor.name == "MyType", invece controlla obj.constructor.name == MyType.name. O semplicemente confrontare i costruttori stessi, tuttavia questo non funzionerà oltre i confini del DOM in quanto vi sono diverse istanze della funzione del costruttore su ciascun DOM, quindi fare un confronto di oggetti sui loro costruttori non funzionerà.


11
Function.namenon fa (ancora) parte dello standard JavaScript. Attualmente è supportato in Chrome e Firefox, ma non in IE (10).
Halcyon,

13
obj.constructor.nameFunziona solo per funzioni con nome . Cioè, se lo definisco var Foo = function() {}, allora per var foo = new Foo(), foo.constructor.nameti darà una stringa vuota.
KFL

29
Attenzione : non fare affidamento su constructor.namese il codice viene minimizzato. Il nome della funzione cambierà arbitrariamente.
igorsantos07


1
@adalbertpl Aveva a che fare con il concatenamento manuale dei prototipi, prima di ES6. È bene sapere che constructor.namesi comporta come previsto con il nuovo supporto di classe in ES6.
devios1

29

Questa funzione restituisce "Undefined"valori non definiti e "Null"null.
Per tutti gli altri valori, CLASSNAMEviene estratta -part [object CLASSNAME], che è il risultato dell'uso Object.prototype.toString.call(value).

function getClass(obj) {
  if (typeof obj === "undefined") return "Undefined";
  if (obj === null) return "Null";
  return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}

getClass("")   === "String";
getClass(true) === "Boolean";
getClass(0)    === "Number";
getClass([])   === "Array";
getClass({})   === "Object";
getClass(null) === "Null";
// etc...

Object.prototype.getClass = function () {usare 'this' invece di obj sarebbe carino
SparK

2
ovviamente quindi null e undefined sarebbero deselezionabili poiché solo l'Oggetto avrebbe il metodo
getClass

8
Funziona solo su oggetti nativi. Se hai una sorta di eredità in corso otterrai sempre "Object".
Halcyon,

Sì, l'ultima riga della funzione dovrebbe essere return obj.constructor.name. Ciò fornisce gli stessi risultati, inoltre gestisce anche oggetti non nativi.
Steve Bennett,

18

Per ottenere la "pseudo classe", puoi ottenere la funzione di costruzione da

obj.constructor

supponendo che constructorsia impostato correttamente quando si fa l'eredità - che è per qualcosa del tipo:

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

e queste due linee, insieme a:

var woofie = new Dog()

farà woofie.constructornotare Dog. Si noti che Dogè una funzione di costruzione ed è un Functionoggetto. Ma puoi farlo if (woofie.constructor === Dog) { ... }.

Se vuoi ottenere il nome della classe come stringa, ho trovato che il seguente funziona bene:

http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects

function getObjectClass(obj) {
    if (obj && obj.constructor && obj.constructor.toString) {
        var arr = obj.constructor.toString().match(
            /function\s*(\w+)/);

        if (arr && arr.length == 2) {
            return arr[1];
        }
    }

    return undefined;
}

Arriva alla funzione di costruzione, la converte in stringa ed estrae il nome della funzione di costruzione.

Si noti che obj.constructor.nameavrebbe potuto funzionare bene, ma non è standard. È su Chrome e Firefox, ma non su IE, incluso IE 9 o IE 10 RTM.


13

È possibile ottenere un riferimento alla funzione di costruzione che ha creato l'oggetto utilizzando la proprietà di costruzione :

function MyObject(){
}

var obj = new MyObject();
obj.constructor; // MyObject

Se è necessario confermare il tipo di un oggetto in fase di esecuzione, è possibile utilizzare l' operatore instanceof :

obj instanceof MyObject // true

non restituisce la funzione di costruzione stessa, come, puoi chiamarla di nuovo e creare un nuovo oggetto di quel tipo?
SparK,

1
@SparK Sì, anche se è ancora possibile utilizzarlo per un confronto purché si trovi sullo stesso DOM (si stanno confrontando oggetti funzione). Tuttavia è molto meglio trasformare il costruttore in una stringa e confrontarlo, in particolare perché funziona oltre i confini del DOM quando si utilizzano iframe.
devios1,

Questa risposta restituisce la "classe" (o almeno un handle dell'oggetto che può essere usato per creare un'istanza della classe - che è la stessa della "classe"). Quanto sopra risponde a tutte le stringhe restituite che non è uguale a "l'oggetto di classe" (per così dire).
Mike P.

8

In linea con il suo record ininterrotto di compatibilità con le versioni precedenti, ECMAScript 6, JavaScript non ha ancora un classtipo (anche se non tutti lo capiscono). Esso ha una classparola chiave come parte della sua classsintassi per la creazione di prototipi-ma ancora nessuna cosa che si chiama classe . JavaScript non è ora e non è mai stato un linguaggio OOP classico . Parlare di JS in termini di classe è solo fuorviante o un segno di eredità prototipica non ancora grokking (solo per mantenerlo reale).

Ciò significa che this.constructorè ancora un ottimo modo per ottenere un riferimento alla constructorfunzione. Ed this.constructor.prototypeè il modo di accedere al prototipo stesso. Dal momento che questo non è Java, non è una classe. È l'oggetto prototipo da cui è stata creata l'istanza della tua istanza. Ecco un esempio usando lo zucchero sintattico ES6 per creare una catena di prototipi:

class Foo {
  get foo () {
    console.info(this.constructor, this.constructor.name)
    return 'foo'
  }
}

class Bar extends Foo {
  get foo () {
    console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
    console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))

    return `${super.foo} + bar`
  }
}

const bar = new Bar()
console.dir(bar.foo)

Questo è ciò che produce usando babel-node:

> $ babel-node ./foo.js                                                                                                                    6.2.0 master ●]
[THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
[SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
[Function: Bar] 'Bar'
'foo + bar'

Ecco qui! Nel 2016, c'è una classparola chiave in JavaScript, ma ancora nessun tipo di classe. this.constructorè il modo migliore per ottenere la funzione di costruzione, this.constructor.prototypeil modo migliore per accedere al prototipo stesso.


7

ho avuto una situazione di lavoro generico ora e ho usato questo:

class Test {
  // your class definition
}

nameByType = function(type){
  return type.prototype["constructor"]["name"];
};

console.log(nameByType(Test));

questo è l'unico modo che ho trovato per ottenere il nome della classe per tipo input se non hai un'istanza di un oggetto.

(scritto in ES2017)

anche la notazione a punti funziona bene

console.log(Test.prototype.constructor.name); // returns "Test" 

Ah, questo è quello che stavo cercando. Se non viene istanziato, devi usare "prototype" per ottenere il nome della classe. Grazie mille!
Artokun,

4

Per le classi Javascript in ES6 è possibile utilizzare object.constructor. Nella classe di esempio seguente il getClass()metodo restituisce la classe ES6 come ci si aspetterebbe:

var Cat = class {

    meow() {

        console.log("meow!");

    }

    getClass() {

        return this.constructor;

    }

}

var fluffy = new Cat();

...

var AlsoCat = fluffy.getClass();
var ruffles = new AlsoCat();

ruffles.meow();    // "meow!"

Se si crea un'istanza della classe dal getClassmetodo, assicurarsi di racchiuderla tra parentesi, ad esruffles = new ( fluffy.getClass() )( args... );


3

Trovo il object.constructor.toString()ritorno [object objectClass]in IE, piuttosto che function objectClass () {}restituito a Chome. Quindi, penso che il codice in http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects potrebbe non funzionare bene in Internet Explorer e ho corretto il codice come segue:

codice:

var getObjectClass = function (obj) {
        if (obj && obj.constructor && obj.constructor.toString()) {

                /*
                 *  for browsers which have name property in the constructor
                 *  of the object,such as chrome 
                 */
                if(obj.constructor.name) {
                    return obj.constructor.name;
                }
                var str = obj.constructor.toString();
                /*
                 * executed if the return of object.constructor.toString() is 
                 * "[object objectClass]"
                 */

                if(str.charAt(0) == '[')
                {
                        var arr = str.match(/\[\w+\s*(\w+)\]/);
                } else {
                        /*
                         * executed if the return of object.constructor.toString() is 
                         * "function objectClass () {}"
                         * for IE Firefox
                         */
                        var arr = str.match(/function\s*(\w+)/);
                }
                if (arr && arr.length == 2) {
                            return arr[1];
                        }
          }
          return undefined; 
    };

2

In JavaScript, non ci sono classi, ma penso che tu voglia il nome del costruttore e obj.constructor.toString()ti dirà di cosa hai bisogno.


1
Ciò restituirà l'intera definizione della funzione di costruzione come una stringa. Quello che vuoi davvero è .name.
devios1

4
ma .namenon è definito nemmeno su IE 9
polarità

1

Concordo con il dfa, ecco perché considero il prototye come la classe quando non è stata trovata alcuna classe con nome

Ecco una funzione aggiornata di quella pubblicata da Eli Gray, per adattarsi al mio modo di pensare

function what(obj){
    if(typeof(obj)==="undefined")return "undefined";
    if(obj===null)return "Null";
    var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
    if(res==="Object"){
        res = obj.constructor.name;
        if(typeof(res)!='string' || res.length==0){
            if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objects
            if(obj instanceof Array)return "Array";// Array prototype is very sneaky
            return "Object";
        }
    }
    return res;
}

1

Se hai bisogno non solo di ottenere la classe GET ma anche di ESTENDERLA dall'avere solo un'istanza, scrivi:

facciamolo

 class A{ 
   constructor(name){ 
     this.name = name
   }
 };

 const a1 = new A('hello a1');

quindi per estendere A con l'istanza usare solo:

const a2 = new ((Object.getPrototypeOf(a)).constructor())('hello a2')
// the analog of const a2 = new A()

console.log(a2.name)//'hello a2'

0

Suggerisco di usare Object.prototype.constructor.name:

Object.defineProperty(Object.prototype, "getClass", {
    value: function() {
      return this.constructor.name;
    }
});

var x = new DOMParser();
console.log(x.getClass()); // `DOMParser'

var y = new Error("");
console.log(y.getClass()); // `Error'

0

Ecco un'implementazione di getClass()egetInstance()

È possibile ottenere un riferimento per la classe di un oggetto utilizzando this.constructor.

Da un contesto di istanza:

function A() {
  this.getClass = function() {
    return this.constructor;
  }

  this.getNewInstance = function() {
    return new this.constructor;
  }
}

var a = new A();
console.log(a.getClass());  //  function A { // etc... }

// you can even:
var b = new (a.getClass());
console.log(b instanceof A); // true
var c = a.getNewInstance();
console.log(c instanceof A); // true

Dal contesto statico:

function A() {};

A.getClass = function() {
  return this;
}

A.getInstance() {
  return new this;
}

2
Perché non solo this.constructor?
Solomon Ucko,

1
Non lo so, ma se è meglio, puoi sicuramente modificare la risposta per migliorarla quando la trovi meglio, dopo tutto questa è una comunità.
Bruno Finger

0

Puoi anche fare qualcosa del genere

 class Hello {
     constructor(){
     }
    }
    
      function isClass (func) {
        return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))
    }
    
   console.log(isClass(Hello))

Questo ti dirà se l'input è di classe o no


-2

Javascript è un linguaggio senza classi: non ci sono classi che definiscono staticamente il comportamento di una classe come in Java. JavaScript utilizza prototipi anziché classi per definire le proprietà degli oggetti, inclusi i metodi e l'ereditarietà. È possibile simulare molte funzionalità di classe con prototipi in JavaScript.


12
Ho spesso detto che Javascript manca di classe :)
Steven

4
Aggiornamento: A partire da ECMAScript 6, JavaScript non ha ancora un classtipo. Esso ha una classparola chiave e classla sintassi per la creazione di prototipi in cui i metodi possono più facilmente accesso super.
james_womack,

-3

La domanda sembra già risposta ma l'OP vuole accedere alla classe di e all'oggetto, proprio come facciamo in Java e la risposta selezionata non è sufficiente (imho).

Con la seguente spiegazione, possiamo ottenere una classe di un oggetto (in realtà è chiamato prototipo in javascript).

var arr = new Array('red', 'green', 'blue');
var arr2 = new Array('white', 'black', 'orange');

Puoi aggiungere una proprietà come questa:

Object.defineProperty(arr,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue

Ma la .lastproprietà sarà disponibile solo per ' arr' l'oggetto che è istanziato dal prototipo Array. Quindi, per avere la .lastproprietà da rendere disponibile per tutti gli oggetti istanziati dal prototipo di array, dobbiamo definire la .lastproprietà per il prototipo di array:

Object.defineProperty(Array.prototype,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Il problema qui è che devi sapere a quale tipo di oggetto (prototipo) appartengono le variabili ' arr' e ' arr2'! In altre parole, se non conosci il tipo di classe (prototipo) arrdell'oggetto ' ', non sarai in grado di definire una proprietà per loro. Nell'esempio sopra, sappiamo che arr è un'istanza dell'oggetto Array, ecco perché abbiamo usato Array.prototype per definire una proprietà per Array. E se non conoscessimo la classe (prototipo) del ' arr'?

Object.defineProperty(arr.__proto__,'last2', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Come puoi vedere, senza sapere che " arr" è un array, possiamo aggiungere una nuova proprietà semplicemente facendo riferimento alla classe di " arr" usando " arr.__proto__".

Abbiamo avuto accesso al prototipo di " arr" senza sapere che si tratta di un'istanza di array e penso che sia stato ciò che OP ha chiesto.


La __proto__proprietà è obsoleta e non ha quasi alcun vantaggio sulla prototypeproprietà.
Sapphire_Brick,
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.