Jak uzyskać klasę obiektu JavaScript?

728

Stworzyłem obiekt JavaScript, ale jak mogę określić klasę tego obiektu?

Chcę czegoś podobnego do .getClass()metody Java .

DNB5brims
źródło
6
na przykład tworzę taką osobę: var p = new Person (); Mam obiekt osoby o nazwie „p”, jak mogę użyć „p”, aby odzyskać nazwę klasy: „osoba”.
DNB5brims
7
Duplikat
Casebash
Aktualizacja: Od ECMAScript 6 JavaScript nadal nie ma classtypu. To nie ma classsłów kluczowych i classskładni do tworzenia prototypów, w której metody mogą łatwiej dostęp super.
james_womack
Co z Object.className?
Paul Basenko
@ Paul-Basenko: „className” nie powie ci klasy obiektu, ale zwróci treść właściwości „class” elementu HTML, która odnosi się do klas CSS. Chcesz także użyć „classList”, aby łatwo nimi zarządzać, ale nie jest to związane z pytaniem PO.
Obsidian

Odpowiedzi:

1009

W getClass()JavaScript nie ma dokładnego odpowiednika Javy . Wynika to głównie z tego, że JavaScript jest językiem opartym na prototypach , w przeciwieństwie do języka Java opartego na klasach .

W zależności od tego, czego potrzebujesz getClass(), w JavaScript jest kilka opcji:

Kilka przykładów:

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

Uwaga: jeśli kompilujesz swój kod za pomocą Uglify, zmieni on nieglobalne nazwy klas. Aby temu zapobiec, Uglify ma --mangleparametr, który można ustawić na wartość false, używając łyka lub chrząknięcia .

hrabia
źródło
6
Prawdopodobnie func.prototypetak powinno być (tak, funkcje są obiektami, ale prototypewłaściwość dotyczy tylko obiektów funkcyjnych).
Mil
5
możesz również wspomnieć instanceof/ isPrototypeOf()i niestandardowy__proto__
Christoph
9
ES5 ma dodatkowoObject.getPrototypeOf()
Christoph
22
Ostrzeżenie : nie polegaj, constructor.namejeśli twój kod jest minimalizowany. Nazwa funkcji zmieni się dowolnie.
igorsantos07
3
@ igorsantos07, przynajmniej w 2019 r .; 5-10 najlepszych wyników Google dla „internetowego javascript minifier” rozpoznaje construction.namejako token, który należy zignorować / nie zminimalizować. Poza tym większość (jeśli nie wszystkie) oprogramowanie minimalizatora zapewnia reguły wyjątków.
vulcan raven
296
obj.constructor.name

to niezawodna metoda w nowoczesnych przeglądarkach. Function.namezostał oficjalnie dodany do standardu w ES6, dzięki czemu jest to zgodny ze standardami sposób uzyskiwania „klasy” obiektu JavaScript jako ciągu. Jeśli obiekt zostanie utworzony za pomocą instancji var obj = new MyClass(), zwróci „MyClass”.

Zwróci „Number” dla liczb, „Array” dla tablic i „Function” dla funkcji itp. Ogólnie działa zgodnie z oczekiwaniami. Jedynymi przypadkami, w których nie udaje się, jest utworzenie obiektu bez prototypu za pośrednictwem Object.create( null )lub utworzenie instancji obiektu z funkcji anonimowo zdefiniowanej (nienazwanej).

Pamiętaj również, że jeśli minimalizujesz swój kod, porównywanie z ciągami znaków zakodowanych na stałe nie jest bezpieczne. Na przykład zamiast sprawdzać, czy obj.constructor.name == "MyType"zamiast tego sprawdź obj.constructor.name == MyType.name. Lub po prostu porównaj same konstruktory, jednak to nie zadziała ponad granicami DOM, ponieważ istnieją różne instancje funkcji konstruktora w każdym DOM, dlatego porównanie obiektów na ich konstruktorach nie zadziała.

devios1
źródło
11
Function.namenie jest (jeszcze) częścią standardu JavaScript. Jest obecnie obsługiwany w Chrome i Firefox, ale nie w IE (10).
Halcyon,
13
obj.constructor.namedziała tylko dla nazwanych funkcji. To znaczy, jeśli zdefiniuję var Foo = function() {}, to dla var foo = new Foo(), foo.constructor.nameda ci pusty ciąg.
KFL
29
Ostrzeżenie : nie polegaj, constructor.namejeśli twój kod jest minimalizowany. Nazwa funkcji zmieni się dowolnie.
igorsantos07
1
Function.name jest częścią ES6, patrz developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Janus Troelsen,
1
@adalbertpl Miało to związek z ręcznym łączeniem prototypów przed ES6. Dobrze jest wiedzieć, że constructor.namezachowuje się zgodnie z oczekiwaniami dzięki obsłudze nowej klasy w ES6.
devios1
29

Ta funkcja zwraca "Undefined"wartości niezdefiniowane i wartości "Null"zerowe.
Dla wszystkich innych wartości CLASSNAMEwyodrębnia się -part [object CLASSNAME], co jest wynikiem użycia 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...
Eli Gray
źródło
Object.prototype.getClass = function () {fajne byłoby użycie „this” zamiast obj
SparK
2
oczywiście wtedy zerowe i niezdefiniowane byłyby niemożliwe do sprawdzenia, ponieważ tylko Obiekt miałby metodę
getClass
8
Działa to tylko na rodzimych obiektach. Jeśli masz jakieś dziedzictwo, zawsze otrzymasz "Object".
Halcyon,
Tak, ostatni wiersz funkcji powinien po prostu być return obj.constructor.name. To daje te same wyniki, a także obsługuje obiekty nienatywne.
Steve Bennett
18

Aby uzyskać „pseudo klasę”, można uzyskać funkcję konstruktora, poprzez

obj.constructor

zakładając, że constructorjest ustawione poprawnie podczas dziedziczenia - co jest przez coś takiego:

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

i te dwie linie, wraz z:

var woofie = new Dog()

wskaże woofie.constructorna Dog. Zauważ, że Dogjest to funkcja konstruktora i Functionobiekt. Ale możesz zrobić if (woofie.constructor === Dog) { ... }.

Jeśli chcesz uzyskać nazwę klasy jako ciąg, znalazłem następujące działające dobrze:

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;
}

Przechodzi do funkcji konstruktora, konwertuje ją na ciąg znaków i wyodrębnia nazwę funkcji konstruktora.

Pamiętaj, że obj.constructor.namemógł działać dobrze, ale nie jest to standard. To jest na Chrome i Firefox, ale nie na IE, w tym IE 9 lub IE 10 RTM.

niepolarność
źródło
13

Możesz uzyskać odwołanie do funkcji konstruktora, która utworzyła obiekt, używając właściwości konstruktora :

function MyObject(){
}

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

Jeśli chcesz potwierdzić typ obiektu w czasie wykonywania, możesz użyć operatora instanceof :

obj instanceof MyObject // true
CMS
źródło
czy nie zwraca samej funkcji konstruktora, na przykład, możesz wywołać ją ponownie i utworzyć nowy obiekt tego typu?
SparK
1
@SparK Tak, choć nadal możesz użyć tego do porównania, dopóki jesteś w tym samym DOM (porównujesz obiekty funkcyjne). Jednak znacznie lepszą praktyką jest przekształcenie konstruktora w ciąg znaków i porównanie go, szczególnie dlatego, że działa on ponad granicami DOM podczas korzystania z ramek iframe.
devios1
Ta odpowiedź zwraca „klasę” (lub przynajmniej uchwyt obiektu, którego można użyć do utworzenia instancji klasy - która jest taka sama jak „klasa”). Powyższe odpowiada na wszystkie zwrócone ciągi, które nie są tym samym co „obiekt klasy” (jakby to był).
Mike P.
8

Zgodnie z nieprzerwanym zapisem kompatybilności wstecznej, ECMAScript 6, JavaScript nadal nie ma classtypu (choć nie wszyscy to rozumieją). To nie ma classsłowa kluczowego w ramach swojej classskładni do tworzenia prototypów, ale nadal nie coś, co nazywa klasa . JavaScript nie jest teraz i nigdy nie był klasycznym językiem OOP . Mówienie o JS w kategoriach klasy jest albo mylące, albo jest oznaką jeszcze nieokreślonego dziedziczenia prototypowego (po prostu utrzymywanie go w stanie rzeczywistym).

Oznacza to, że this.constructorwciąż jest doskonałym sposobem na uzyskanie odniesienia do constructorfunkcji. I this.constructor.prototypejest to sposób na uzyskanie dostępu do samego prototypu. Ponieważ nie jest to Java, nie jest to klasa. Jest to obiekt prototypowy, z którego tworzona jest instancja. Oto przykład użycia cukru syntaktycznego ES6 do stworzenia łańcucha prototypów:

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)

Oto, co wyprowadza za pomocą 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'

Masz to! W 2016 r. W classJavaScript jest słowo kluczowe, ale nadal nie ma typu klasy. this.constructorto najlepszy sposób na uzyskanie funkcji konstruktora, this.constructor.prototypenajlepszy sposób na uzyskanie dostępu do samego prototypu.

james_womack
źródło
7

Miałem teraz okazję do ogólnej pracy i skorzystałem z tego:

class Test {
  // your class definition
}

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

console.log(nameByType(Test));

to jedyny sposób, w jaki udało mi się uzyskać nazwę klasy według typu input, jeśli nie masz instancji obiektu.

(napisane w ES2017)

notacja kropkowa również działa dobrze

console.log(Test.prototype.constructor.name); // returns "Test" 
mtizziani
źródło
Ach właśnie tego szukałem. Jeśli nie zostanie utworzona instancja, musisz użyć „prototypu”, aby uzyskać nazwę klasy. Wielkie dzięki!
Artokun
4

W przypadku klas Javascript w ES6 możesz użyć object.constructor. W przykładowej klasie poniżej getClass()metoda zwraca klasę ES6 zgodnie z oczekiwaniami:

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!"

Jeśli tworzysz instancję klasy z getClassmetody, upewnij się, że otaczasz ją nawiasami npruffles = new ( fluffy.getClass() )( args... );

Hugheth
źródło
3

Znajduję object.constructor.toString()zwrot [object objectClass]w IE, a nie function objectClass () {}w chome. Myślę więc, że kod w http://blog.magnetiq.com/post/514962277/finding-out-out-class-names-of-javascript-objects może nie działać dobrze w IE.I poprawiłem kod w następujący sposób:

kod:

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; 
    };
zzy7186
źródło
2

W javascript nie ma klas, ale myślę, że chcesz nazwę konstruktora i obj.constructor.toString()powie ci, czego potrzebujesz.

Jikhan
źródło
1
Zwróci to całą definicję funkcji konstruktora jako ciąg. To, czego naprawdę chcesz .name.
devios1
4
ale .namenie jest zdefiniowany nawet w IE 9
nonpolarity
1

Zgadzam się z dfa, dlatego uważam prototye za klasę, gdy nie znaleziono nazwanej klasy

Oto ulepszona funkcja opublikowana przez Eli Graya, pasująca do mojego sposobu myślenia

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;
}
Antkhan
źródło
1

Jeśli chcesz nie tylko uzyskać klasę, ale także WYDŁUŻYĆ ją tylko o instancję, napisz:

chodźmy

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

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

więc aby rozszerzyć A, mając instancję, użyj tylko:

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

console.log(a2.name)//'hello a2'
AlexNikonov
źródło
0

Sugeruję użycie 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'
Sapphire_Brick
źródło
0

Oto implementacja getClass()igetInstance()

Możesz uzyskać odwołanie do klasy Object za pomocą this.constructor.

Z kontekstu instancji:

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

Ze statycznego kontekstu:

function A() {};

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

A.getInstance() {
  return new this;
}
Bruno Finger
źródło
2
Dlaczego nie tylko this.constructor?
Solomon Ucko
1
Nie wiem, ale jeśli jest lepiej, możesz z pewnością edytować odpowiedź, aby ją poprawić, gdy znajdziesz się lepiej, w końcu to jest społeczność.
Bruno Finger
0

Możesz także zrobić coś takiego

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

Dzięki temu dowiesz się, czy dane wejściowe są klasy, czy nie

iRohitBhatia
źródło
-2

JavaScript jest językiem bezklasowym: nie ma klas, które definiowałyby zachowanie klasy statycznie jak w Javie. JavaScript używa prototypów zamiast klas do definiowania właściwości obiektów, w tym metod i dziedziczenia. Możliwe jest symulowanie wielu funkcji opartych na klasach za pomocą prototypów w JavaScript.

dfa
źródło
12
Często mówiłem, że Javascript nie ma klasy :)
Steven
4
Aktualizacja: Od ECMAScript 6 JavaScript nadal nie ma classtypu. To nie ma classsłów kluczowych i classskładni do tworzenia prototypów, w której metody mogą łatwiej dostęp super.
james_womack
-3

Pytanie wydaje się już udzielone, ale OP chce uzyskać dostęp do klasy i obiektu, tak jak robimy to w Javie, a wybrana odpowiedź nie jest wystarczająca (imho).

Dzięki poniższemu wyjaśnieniu możemy uzyskać klasę obiektu (tak naprawdę w javascript nazywa się to prototypem).

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

Możesz dodać taką właściwość:

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

Ale .lastwłaściwość będzie dostępna tylko dla arrobiektu, który jest utworzony z prototypu Array. Aby więc .lastwłaściwość była dostępna dla wszystkich obiektów utworzonych z prototypu Array, musimy zdefiniować .lastwłaściwość dla prototypu Array:

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

Problem polega na tym, że musisz wiedzieć, do jakiego typu obiektu (prototypu) należą zmienne „ arr” i „ arr2”! Innymi słowy, jeśli nie znasz typu klasy (prototypu) obiektu „ arr”, nie będziesz w stanie zdefiniować dla nich właściwości. W powyższym przykładzie wiemy, że arr jest instancją obiektu Array, dlatego użyliśmy Array.prototype do zdefiniowania właściwości dla Array. Ale co, jeśli nie znamy klasy (prototypu) „ arr”?

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

Jak widać, nie wiedząc, że „ arr” jest tablicą, możemy dodać nową właściwość, po prostu odwołując się do klasy „ arr” za pomocą „ arr.__proto__”.

Udało nam się uzyskać dostęp do prototypu „ arr”, nie wiedząc, że jest to instancja Array i myślę, że o to poprosił OP.

Ramazan Polat
źródło
__proto__Nieruchomość jest przestarzała i nie ma prawie żadnej przewagi nad prototypeobiektem.
Sapphire_Brick