Získejte název typu objektu

Existuje JavaScript ekvivalent Java 's class.getName() ?

Odpověď

Existuje JavaScriptový ekvivalent Java class.getName() ?

Ne .

Aktualizace ES2015 :název class Foo {} je Foo.name . Název thing 's class, bez ohledu na thing 's type, je thing.constructor.name . Vestavěné konstruktory v prostředí ES2015 mají správný name vlastnictví; například (2).constructor.name je "Number" .

Ale tady jsou různé hacky, které všechny padají tak či onak:

Zde je hack, který udělá to, co potřebujete – uvědomte si, že upravuje prototyp objektu, něco, na co se lidé mračí (obvykle z dobrého důvodu)

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

Nyní budou mít všechny vaše objekty funkci getName() , který vrátí jméno konstruktoru jako řetězec. Testoval jsem to v FF3 a IE7 , nemohu mluvit za jiné implementace.

Pokud to nechcete dělat, zde je diskuze o různých způsobech určování typů v JavaScriptu…

Nedávno jsem to aktualizoval, aby to bylo trochu vyčerpávající, i když to není tak úplně ono. Opravy vítány…

Pomocí constructor vlastnost…

Každých object má hodnotu pro jeho constructor vlastnost, ale v závislosti na tom, jak to object byla vytvořena stejně jako to, co chcete s touto hodnotou dělat, může nebo nemusí být užitečné.

Obecně řečeno, můžete použít constructor vlastnost pro testování typu objektu takto:

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

Takže to funguje dostatečně dobře pro většinu potřeb. To znamená…

Upozornění

Nebude fungovat VŮBEC v mnoha případech

Tento vzorec, i když je přerušený, je docela běžný:

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

Objects vytvořeno pomocí new Thingy bude mít constructor vlastnost, která ukazuje na Object , nikoli Thingy . Takže padáme hned na začátku; constructor prostě nemůžete věřit v kódové základně, kterou nemáte pod kontrolou.

Vícenásobná dědičnost

Příkladem, kdy to není tak zřejmé, je použití vícenásobné dědičnosti:

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

Věci nyní nefungují tak, jak byste mohli očekávat:

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

Pokud tedy object, můžete získat neočekávané výsledky vaše testování má jinou hodnotu object nastavit jako jeho prototype . Existují způsoby, jak to obejít mimo rámec této diskuse.

constructor má i jiné využití majetek, některé zajímavé, jiné méně; prozatím se těmito způsoby použití nebudeme zabývat, protože to není pro tuto diskusi relevantní.

Nebude fungovat mezi snímky a okny

Pomocí .constructor protože kontrola typu se přeruší, když chcete zkontrolovat typ objektů pocházejících z různých window objekty, řekněme to iframe nebo vyskakovací okno. Je to proto, že existuje jiná verze každého typu jádra constructor v každém „okně“, tj.

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

Pomocí instanceof operátor…

instanceof Operátor je čistý způsob testování object typ také, ale má své vlastní potenciální problémy, stejně jako constructor vlastnost.

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

Ale instanceof nefunguje pro hodnoty literálu (protože literály nejsou Objects )

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

Literály musí být zabaleny do Object v pořadí instanceof například pracovat

new Number(3) instanceof Number // true

.constructor check funguje dobře pro literály, protože . vyvolání metody implicitně zabalí literály do jejich příslušného typu objektu

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

Proč dvě tečky za 3? Protože Javascript interpretuje první tečku jako desetinnou čárku 😉

Nebude fungovat mezi snímky a okny

instanceof také nebude fungovat v různých oknech, ze stejného důvodu jako constructor kontrola majetku.

Pomocí name vlastnost constructor vlastnost…

Nefunguje VŮBEC v mnoha případech

Opět viz výše; je to docela běžné pro constructor být naprosto a úplně nesprávný a zbytečný.

NEFUNGUJE v

Pomocí myObjectInstance.constructor.name vám poskytne řetězec obsahující název constructor použita funkce, ale podléhá upozorněním ohledně constructor vlastnost, která byla zmíněna dříve.

Pro IE9 a vyšší můžete opici provést opravu:

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

Aktualizovaná verze z dotyčného článku. Toto bylo přidáno 3 měsíce po zveřejnění článku, toto je doporučená verze, kterou by měl použít autor článku Matthew Scharley. Tato změna byla inspirována komentáři poukazujícími na potenciální úskalí v předchozím kódu.

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

Použití Object.prototype.toString

Ukázalo se, že v podrobnostech tohoto příspěvku můžete použít Object.prototype.toString – nízká úroveň a obecná implementace toString – získat typ pro všechny vestavěné typy

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

Dalo by se napsat krátkou pomocnou funkci, jako je

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

odstranit cruft a získat pouze název typu

type('abc') // String

Vrátí však Object pro všechny uživatelem definované typy.

Upozornění pro všechny…

Všechny tyto podléhají jednomu potenciálnímu problému, a tím je otázka, jak byl předmětný objekt zkonstruován. Zde jsou různé způsoby vytváření objektů a hodnoty, které různé metody kontroly typu vrátí:

// 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

I když v této sadě příkladů nejsou přítomny všechny permutace, doufejme, že jich je dost, aby vám poskytly představu o tom, jak by se věci mohly v závislosti na vašich potřebách objevit. Nic nepředpokládejte, pokud přesně nerozumíte tomu, o co vám jde, můžete skončit s prolomením kódu tam, kde to neočekáváte, a to kvůli nedostatečnému prozkoumání jemností.

POZNÁMKA:

Diskuse o typeof Operátor se může zdát do očí bijícím opomenutím, ale ve skutečnosti to není užitečné při identifikaci, zda object je daný typ, protože je velmi zjednodušený. Pochopení, kde typeof je užitečné je důležité, ale v současné době nemám pocit, že je to pro tuto diskuzi nějak zvlášť důležité. Moje mysl je však otevřená změnám. 🙂