Як отримати клас об’єкта JavaScript?


728

Я створив об’єкт JavaScript, але як я можу визначити клас цього об’єкта?

Я хочу щось подібне до .getClass()методу Java .


6
наприклад, я роблю Особу так: var p = new Person (); У мене є об'єкт Person, який називається "p", як я можу використовувати "p" для повернення назви класу: "Person".
DNB5brims


Оновлення: Станом на ECMAScript 6 JavaScript досі не має classтипу. У нього є classключове слово та classсинтаксис для створення прототипів, в яких методи можуть легше отримати доступ super.
james_womack

Що з Object.className?
Павло Басенко

@ Paul-Basenko: "className" не скаже вам клас об'єкта, але поверне вміст властивості "class" HTML-елемента, що відноситься до класів CSS. Ви також хочете використовувати "classList", щоб легко ними керувати, але це не пов'язано з питанням ОП.
Обсидіан

Відповіді:


1009

У JavaScript немає точного аналога Java getClass(). Переважно це пов'язано з тим, що 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 для "он-лайн minifier mini" визнають construction.nameмаркером, який слід ігнорувати / не мінімізувати. Крім того, більшість (якщо не всі) програмного забезпечення minifier містять правила виключення.
вулкан ворон

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


11
Function.nameще не є частиною стандарту JavaScript. На даний момент він підтримується в Chrome і Firefox, але не в IE (10).
Гельсіон

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/…
Janus Troelsen

1
@adalbertpl Це стосувалося вручну ланцюжків прототипів, перш ніж ES6. Добре знати, constructor.nameяк поводиться, як очікувалося, з новою підтримкою класу в ES6.
devios1

29

Ця функція повертається "Undefined"для невизначених значень та "Null"для 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 () {використовувати "це" замість obj було б добре
SparK

2
звичайно, тоді недійсне і невизначене буде неможливим, оскільки тільки Об'єкт матиме метод
getClass

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.


13

Ви можете отримати посилання на функцію конструктора, яка створила об'єкт, використовуючи властивість конструктора :

function MyObject(){
}

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

Якщо вам потрібно підтвердити тип об’єкта під час виконання, ви можете використовувати оператор instanceof :

obj instanceof MyObject // true

чи не повертається сама функція конструктора, наприклад, ви можете викликати її ще раз і створити новий об'єкт цього типу?
SparK

1
@SparK Так, хоча ви все ще можете використовувати це для порівняння, поки ви знаходитесь в одному DOM (ви порівнюєте об'єкти функцій). Однак набагато кращою практикою є перетворення конструктора на рядок і порівняння цього, зокрема, оскільки він працює через межі DOM при використанні iframes.
devios1

Ця відповідь повертає "клас" (або принаймні обробляти об'єкт, який може бути використаний для створення екземпляра класу - що таке саме, як "клас"). Вищенаведене відповідає на всі повернуті рядки, які не збігаються з "об'єктом класу" (як би).
Майк П.

8

Відповідно до свого безперервного запису про сумісність із зворотним рівнем, ECMAScript 6, JavaScript досі не має classтипу (хоча це не всі розуміють). У нього є classключове слово як частина його classсинтаксису для створення прототипів, але все ще жодна річ не називається класом . JavaScript зараз не є і ніколи не був класичною мовою OOP . Говорячи про 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найкращий спосіб отримати доступ до самого прототипу.


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" 

Ах це те, що я шукав. Якщо це не миттєво, вам потрібно використовувати "прототип", щоб отримати ім'я класу. Дякую тонну!
Артокун

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


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

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

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'

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'

0

Ось реалізація getClass()таgetInstance()

Ви можете отримати довідку для класу Object, використовуючи 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))

Це підкаже, чи є вхід класом чи ні


-2

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


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', не знаючи, що це екземпляр масиву, і я думаю, що це запитало ОП.


__proto__Властивість є застарілим і практично не має переваг над prototypeвласністю.
Sapphire_Brick
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.