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

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

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

Ответ 1

В JavaScript нет точного аналога Java getClass(). В основном это связано с тем, что JavaScript был языком прототипа, в отличие от Java, являющегося class-based один.

В зависимости от того, что вам нужно getClass() for, в 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.

Ответ 2

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 имеются разные экземпляры функции конструктора, поэтому сравнение объектов на их конструкторах не будет работать.

Обратите внимание при объединении прототипов

Изменение: Это очевидно спорный теперь, когда ES6 имеет лучшую поддержку классов и наследования. Как объясняет adalbertpl, constructor.name ведет себя так, как ожидается в этом сценарии.

Как ни странно, constructor.name возвращает имя самой базовой функции, используемой в цепочке прототипов, что, к сожалению, не интуитивно понятно. Например, если B наследует прототип из A и вы создаете новый экземпляр B, b, b.constructor.name возвращает "A", что кажется неправильным. Однако он отлично работает для одноуровневых прототипов и всех примитивов.

Ответ 3

Эта функция возвращает либо "undefined", "null", либо "class" в [object class] из Object.prototype.toString.call(someObject).

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

Ответ 4

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

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.

Ответ 5

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

function MyObject(){
}

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

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

obj instanceof MyObject // true

Ответ 6

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

Это означает, что 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 лучший способ получить доступ к самому прототипу.

Ответ 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" 

Ответ 8

Я нахожу object.constructor.toString() return [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; 
    };

Ответ 9

Для классов 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... );

Ответ 10

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

Ответ 11

Согласитесь с 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;
}

Ответ 12

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

Ответ 13

Попробуйте мою библиотеку машинописных классов-помощников:

import { CLASS } from 'typescript-class-helpers'

@CLASS.NAME('Example')
class Example {

}

console.log(CLASS.getName(Example) === 'Example') // true
console.log(CLASS.getNameFromObject(new Example()) === 'Example') // true
console.log(CLASS.getBy('Example') === Example) // true

Таким образом, вы можете использовать свои имена классов даже после процесса uglify.

Монтаж:

npm i typescript-class-helpers

Ответ 14

Здесь реализация getClass() и getInstance()

Вы можете получить ссылку для класса Object с помощью window.

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

function A() {
    this.getClass = function() {
        return window[this.constructor.name];
    }

    this.getNewInstance = function() {
        return new window[this.constructor.name];
    }
}

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

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

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

function B() {};

B.getClass = function() {
    return window[this.name];
}

B.getInstance() {
    return new window[this.name];
}

Ответ 15

Вопрос кажется уже отвеченным, но OP хочет получить доступ к классу и объекту, точно так же, как мы делаем на 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" является массивом, мы можем добавить новое свойство, просто bu ссылающееся на класс "arr" , используя "arr.__proto__".

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