Как получить класс объекта JavaScript?

729

Я создал объект JavaScript, но как я могу определить класс этого объекта?

Я хочу что-то похожее на .getClass()метод Java .

DNB5brims
источник
6
например, я делаю Person следующим образом: var p = new Person (); У меня есть объект Person, который называется «p», как я могу использовать «p», чтобы вернуть имя класса: «Person».
DNB5brims
7
Дубликат
Casebash
Обновление: Начиная с ECMAScript 6, JavaScript все еще не имеет classтипа. У него есть classключевое слово и classсинтаксис для создания прототипов, к которым методы могут получить более легкий доступ super.
james_womack
Как насчет Object.className?
Павел
@ Paul-Basenko: «className» не сообщит вам класс объекта, но вернет содержимое свойства «class» HTML-элемента, которое ссылается на CSS-классы. Вы также хотите использовать «classList» для легкого управления ими, но это не связано с вопросом ОП.
Обсидиан

Ответы:

1011

Там нет точного аналога Java getClass()в JavaScript. В основном это связано с тем, что JavaScript является языком на основе прототипов , а не Java классов .

В зависимости от того, что вам нужно getClass(), в JavaScript есть несколько опций:

Несколько примеров:

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

Примечание: если вы компилируете свой код с помощью Uglify, он изменит неглобальные имена классов. Чтобы предотвратить это, в Uglify есть --mangleпараметр, который вы можете установить в false, используя gulp или grunt .

граф
источник
6
Вероятно, так и должно быть func.prototype(да, функции являются объектами, но prototypeсвойство относится только к объектам функций).
Майлз
5
Вы также можете упомянуть instanceof/ isPrototypeOf()и нестандартные__proto__
Кристоф
9
ES5 имеет дополнительноObject.getPrototypeOf()
Кристоф
22
Предупреждение : не полагайтесь, constructor.nameесли ваш код минимизируется. Имя функции будет меняться произвольно.
igorsantos07
3
@ igorsantos07, по крайней мере, в 2019 году; 5-10 лучших результатов поиска Google по "миниатюре javascript в Интернете" распознаются construction.nameкак токены, которые следует игнорировать / не минимизировать. Кроме того, большинство (если не все) программы-минификаторы предоставляют правила исключений.
вулкан ворон
297
obj.constructor.name

это надежный метод в современных браузерах. Function.nameбыл официально добавлен к стандарту в ES6, что делает его совместимым со стандартами средством получения «класса» объекта JavaScript в виде строки. Если объект создан с помощью var obj = new MyClass(), он вернет «MyClass».

Он вернет «Число» для чисел, «Массив» для массивов и «Функция» для функций и т. Д. Обычно он ведет себя как ожидалось. Единственные случаи, когда он терпит неудачу, это если объект создается без прототипа, с помощью Object.create( null ), или объект был создан из анонимно определенной (неназванной) функции.

Также обратите внимание, что если вы минимизируете свой код, сравнивать его с жестко-закодированными строками типов небезопасно. Например, вместо проверки, если obj.constructor.name == "MyType"вместо проверки obj.constructor.name == MyType.name. Или просто сравните сами конструкторы, однако это не сработает через границы DOM, поскольку в каждом DOM есть разные экземпляры функции конструктора, поэтому сравнение объектов на их конструкторах не будет работать.

devios1
источник
11
Function.nameне является (пока) частью стандарта JavaScript. В настоящее время он поддерживается в Chrome и Firefox, но не в IE (10).
Halcyon
13
obj.constructor.nameработает только для именованных функций. То есть, если я определяю var Foo = function() {}, то для var foo = new Foo(), foo.constructor.nameдаст вам пустую строку.
KFL
29
Предупреждение : не полагайтесь, constructor.nameесли ваш код минимизируется. Имя функции будет меняться произвольно.
igorsantos07
1
Function.name является частью ES6 см developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Янус Troelsen
1
@adalbertpl Это было связано с созданием вручную прототипов до ES6. Хорошо знать, что constructor.nameведет себя как ожидалось с поддержкой нового класса в ES6.
devios1
29

Эта функция возвращает "Undefined"неопределенные значения и "Null"нулевое значение.
Для всех других значений CLASSNAMEизвлекается -part из [object CLASSNAME], что является результатом использования 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 () {было бы неплохо использовать 'this' вместо obj
SparK
2
конечно, тогда null и undefined будут не проверяемы, поскольку только у объекта будет метод getClass
SparK
8
Это работает только на нативных объектах. Если у вас есть какое-то наследство, вы всегда получите его "Object".
Halcyon
Да, последняя строка функции должна быть просто return obj.constructor.name. Это дает те же результаты, а также обрабатывает не собственные объекты.
Стив Беннетт
18

Чтобы получить «псевдокласс», вы можете получить функцию конструктора,

obj.constructor

Предполагая, что constructorправильно установлен, когда вы делаете наследование - что-то вроде:

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

и эти две строки вместе с:

var woofie = new Dog()

будет woofie.constructorуказывать на Dog. Обратите внимание, что Dogэто функция конструктора и Functionобъект. Но вы можете сделать if (woofie.constructor === Dog) { ... }.

Если вы хотите получить имя класса в виде строки, я обнаружил, что следующее работает хорошо:

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

Он попадает в функцию конструктора, преобразует ее в строку и извлекает имя функции конструктора.

Обратите внимание, что это obj.constructor.nameмогло бы хорошо сработать, но это не стандартно. Это на Chrome и Firefox, но не на IE, включая IE 9 или IE 10 RTM.

nonopolarity
источник
13

Вы можете получить ссылку на функцию конструктора, которая создала объект, используя свойство конструктора :

function MyObject(){
}

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

Если вам нужно подтвердить тип объекта во время выполнения, вы можете использовать оператор instanceof :

obj instanceof MyObject // true
CMS
источник
разве она не возвращает саму функцию конструктора, например, вы можете вызвать ее снова и создать новый объект этого типа?
SparK
1
@SparK Да, хотя вы все равно можете использовать это для сравнения, если вы находитесь в том же DOM (вы сравниваете функциональные объекты). Однако гораздо лучше превратить конструктор в строку и сравнить ее, особенно потому, что он работает через границы DOM при использовании iframes.
devios1
Этот ответ возвращает «класс» (или, по крайней мере, дескриптор объекта, который можно использовать для создания экземпляра класса, который совпадает с «классом»). Вышеприведенный ответ отвечает на все возвращаемые строки, которые не совпадают с «объектом класса» (как это было).
Майк П.
8

В соответствии со своей непрерывной записью обратной совместимости, ECMAScript 6, JavaScript все еще не имеет classтипа (хотя не все это понимают). У него есть classключевое слово как часть его classсинтаксиса для создания прототипов, но по- прежнему ничего не называется класс . JavaScript не сейчас и имеет не был классическим языком ООП . Говоря о JS с точки зрения класса, это либо вводит в заблуждение, либо является признаком того, что еще не уклоняется от прототипного наследования (просто сохраняя его реальным).

Это означает, что this.constructorэто по-прежнему отличный способ получить ссылку на constructorфункцию. И this.constructor.prototypeэто способ получить доступ к самому прототипу. Поскольку это не Java, это не класс. Это объект-прототип, из которого был создан экземпляр. Вот пример использования синтаксического сахара ES6 для создания цепочки прототипов:

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)

Это то, что это выводит, используя 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'

Вот оно! В 2016 году classв JavaScript есть ключевое слово, но все еще нет типа класса. this.constructorэто лучший способ получить функцию конструктора, this.constructor.prototypeлучший способ получить доступ к самому прототипу.

james_womack
источник
7

у меня была ситуация, чтобы работать сейчас общий и использовал это:

class Test {
  // your class definition
}

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

console.log(nameByType(Test));

это единственный способ получить имя класса по типу ввода, если у вас нет экземпляра объекта.

(написано в ES2017)

Точечная запись также отлично работает

console.log(Test.prototype.constructor.name); // returns "Test" 
mtizziani
источник
Ах, это то, что я искал. Если он не создан, вы должны использовать 'prototype', чтобы получить имя класса. Благодаря тонну!
Артокун
4

Для классов Javascript в ES6 вы можете использовать object.constructor. В приведенном ниже примере класса getClass()метод возвращает класс ES6, как и следовало ожидать:

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

Если вы создаете экземпляр класса из getClassметода, убедитесь, что вы заключили его в скобки, напримерruffles = new ( fluffy.getClass() )( args... );

Hugheth
источник
3

Я нахожу object.constructor.toString()возвращение [object objectClass]в IE, а не function objectClass () {}возвращение в chome. Итак, я думаю, что код в http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects может не работать в IE. И я исправил код следующим образом:

код:

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
источник
2

В javascript нет классов, но я думаю, что вы хотите имя конструктора и obj.constructor.toString()скажете, что вам нужно.

Джихан
источник
1
Это вернет все определение функции конструктора в виде строки. То, что вы действительно хотите, это .name.
devios1
4
но .nameне определено даже в IE 9
неполярность
1

Согласитесь с dfa, поэтому я рассматриваю прототип как класс, когда не найдено ни одного именованного класса

Вот обновленная функция, опубликованная Эли Греем, в соответствии с моим мнением

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
источник
1

Если вам нужно не только получить класс GET, но и расширить его, добавив только экземпляр, напишите:

Давайте

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

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

Таким образом, чтобы расширить A, используя только экземпляр:

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

console.log(a2.name)//'hello a2'
AlexNikonov
источник
0

Я предлагаю использовать 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
источник
0

Вот реализация getClass()иgetInstance()

Вы можете получить ссылку на класс объекта, используя this.constructor.

Из контекста экземпляра:

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

Из статического контекста:

function A() {};

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

A.getInstance() {
  return new this;
}
Бруно Фингер
источник
2
Почему не просто this.constructor?
Соломон Уцко
1
Я не знаю, но если это лучше, вы можете отредактировать ответ, чтобы улучшить его, как вам будет лучше, ведь это сообщество.
Бруно Фингер
0

Вы также можете сделать что-то вроде этого

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

Это скажет вам, если вход является классом или нет

iRohitBhatia
источник
-2

Javascript - это язык без классов: нет классов, которые бы определяли поведение класса статически, как в Java. JavaScript использует прототипы вместо классов для определения свойств объекта, включая методы и наследование. Можно моделировать многие функции классов на основе прототипов в JavaScript.

DFA
источник
12
Я часто говорил, что в Javascript отсутствует класс :)
Стивен,
4
Обновление: Начиная с ECMAScript 6, JavaScript все еще не имеет classтипа. У него есть classключевое слово и classсинтаксис для создания прототипов, к которым методы могут получить более легкий доступ super.
james_womack
-3

Кажется, вопрос уже получен, но ОП хочет получить доступ к классу и объекту, как мы делаем в Java, и выбранного ответа недостаточно (imho).

С помощью следующего объяснения мы можем получить класс объекта (на самом деле он называется прототипом в javascript).

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

Вы можете добавить свойство как это:

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

Но .lastсвойство будет доступно только для arrобъекта, который создается из прототипа Array. Итак, чтобы .lastсвойство было доступно для всех объектов, созданных из прототипа Array, мы должны определить .lastсвойство для прототипа Array:

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

Проблема в том, что вы должны знать, к какому типу объекта (прототипу) относятся переменные ' arr' и ' arr2'! Другими словами, если вы не знаете тип класса (прототип) объекта ' arr', то вы не сможете определить свойство для них. В приведенном выше примере мы знаем, что arr является экземпляром объекта Array, поэтому мы использовали Array.prototype, чтобы определить свойство для Array. Но что, если мы не знали класс (прототип) ' arr'?

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

Как видите, не зная, что ' arr' является массивом, мы можем добавить новое свойство, просто ссылаясь на класс ' arr' с помощью 'arr.__proto__ '.

Мы получили доступ к прототипу ' arr', не зная, что это экземпляр Array, и я думаю, что об этом спросил OP.

Рамазан Полат
источник
__proto__Свойство является устаревшим и практически не имеет преимущества передprototype собственностью.
Sapphire_Brick