1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PARONYMAdvent Calendar 2021

Day 22

JavaScriptでインスタンスのクラス名を取得する方法

Last updated at Posted at 2021-12-21

はじめに

この記事は PARONYM Advent Calendar 2021 の22日目の記事です。

tl;dr

/**
 * クラス名/関数名(Function)を取得する
 * @param {*} obj インスタンス。プリミティブ型でもいい
 * @returns {String}
 */
function getClass(obj) {
    if (obj === null) {
        return 'null';
    }
    if (obj === undefined) {
        return 'undefined';
    }
    return obj.constructor.name;
}

JavaScriptのクラスとクラス名とは

ECMAScript5でJavaScriptに正式にclassが導入されました。classで宣言されたものがクラスです。
、、、なら単純ですがJavaScriptでclassの実態は今でもFunctionです。 function hogehoge() {} で宣言されるアレです。
クラスには constructor() というクラスの初期化メソッドが導入されました。なので全てのクラスは constructor() というメソッド/関数を持ちます。
なのでそのメソッドの名前を調べるのが1番確実です。

背景と解説

クラスはFunctionです。
Functionには name プロパティがあり参照できます。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/name

function ForExampleClass() {}
let name = ForExampleClass.name;

でもインスタンスからたどってもそんなものはありません。

function ForExampleClass1() {}
let obj1 = new ForExampleClass1();
let name1_1 = ForExampleClass1.name; // これはOK
let name1_2 = obj1.name; // undefined

namethis に設定してもそれは望んでいるものではありません。

function ForExampleClass2() {
    this.name = 'invalid';
}
let obj2 = new ForExampleClass2();
let name2_1 = ForExampleClass2.name; // これはOK
let name2_2 = obj2.name; // 望んでいるものではない

prototype を使って name を設定してもそれも望んでいるものではありません。

function ForExampleClass3() {}
ForExampleClass3.prototype.name = 'invalid';
let obj3 = new ForExampleClass3();
let name3_1 = ForExampleClass3.name; // これはOK
let name3_2 = ForExampleClass3.prototype.name; // 望んでいるものではない
let name3_3 = obj3.name; // 望んでいるものではない

this に定義しても望んでいるものではありません。

function ForExampleClass4() {
    this.name = 'invalid';
}
let obj4 = new ForExampleClass4();
ForExampleClass4.name = 'invalid';
ForExampleClass4.prototype.name = 'invalid';
let name4_1 = ForExampleClass4.name; // これはOK
let name4_2 = ForExampleClass4.prototype.name; // undefined
let name4_3 = obj4.name; // 望んでいるものではない

それならオブジェクトから文字列を求めるならメソッド名にそんな物があったよね、というのがこれです。おしい。

function ForExampleClass5() {}
ForExampleClass5.prototype.toString = () => { return 'ForExampleClass5'; }
let obj5 = new ForExampleClass5();
let name5_1 = ForExampleClass5.name; // これはOK
let name5_2 = obj5.toString(); // これはOK
let name5_3 = Object.prototype.toString.call(obj5); // 望んでいるものではない

仕方ないのでclass機能を使うか〜となったのがこれですね。目的は達成できていますが定義が難しいですね。

class ForExampleClass6 {
    get [Symbol.toStringTag]() { return 'ForExampleClass5'; }
}
let obj6 = new ForExampleClass5();
let name6_1 = ForExampleClass6.name; // これはOK
let name6_2 = Object.prototype.toString.call(obj6); // これはOK

最終的にclassを使うなら constructor がいるならそれでしょというのがこれです。

class ForExampleClass7 {}
let obj7 = new ForExampleClass7();
let name7_1 = ForExampleClass7.name; // これはOK
let name7_2 = obj7.constructor.name; // これはOK

というわけでインスタンスからクラス名を取得する関数は最初の通りこうなりました。

/**
 * クラス名/関数名(Function)を取得する
 * @param {*} obj インスタンス。プリミティブ型でもいい
 * @returns {String}
 */
function getClass(obj) {
    if (obj === null) {
        return 'null';
    }
    if (obj === undefined) {
        return 'undefined';
    }
    return obj.constructor.name;
}
function ForExampleClass8() {}
let obj8 = new ForExampleClass8();
let name8_1 = ForExampleClass8.name; // これはOK
let name8_2 = getClass(obj8); // これはOK
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?