[javascript]クラスの名前を調べる

ログウインドウの右端にファイル名が付くけど、クラス名も書き出したい。

class xxxx{
  static className = this.name;
  ...
}

は安定してクラス名が取得できるが、これは、staticなメソッドのみ参照可能で、インスタンス依存のメソッド用に

class xxxx{
  className;
  constructor() {
    this.className = this.name;
    ...
  }
  ...
}

class xxxx{
  className;
  constructor() {
    this.className = this.constructor.name;
    ...
  }
  ...
}

のいづれかが必要だった。どっちが常に正しいという訳では無いので、

static className = this.name;
className;
constructor() {
  this.className = this.name ?? this.constructor.name;
  ...
}

~なぁあたりが良さそうだ。

??はあまり使わないけど、Null 合体演算子で、

「とりあえず【まともな値】を返す」場合に便利な演算子。

新しいパターンが増えたら

static className = this.name;
className;
constructor() {
  this.className = this.name ?? this.constructor.name ?? {新しいパターン};
  ...
}

にすればいいだろう。

これで各メソッドに

    メソッド名 (...) {
        const methodName = '{メソッド名}';
        console.debug(`${this.className}.${methodName}(...)`);

と書ける。

例外処理を発生してスタックを調べる事もできたけど、イマイチ感がある。

const getCurrentLineInfo = () => {
    try {
        throw new Error('getCurrentLineInfo Error');
    } catch (ex) {
        let stack = ex.stack.split('\n');
        let target = stack[2];
        // パターン1:at xxClass.yyMethod (https://{domain}/{path}/{filename}:{line}:{column})
        // パターン2:at xxClass.yyMethod (file:///{drive}/{path}/{filename}:{line}:{column})
        let match = target.match(/\s*at\s*([_a-zA-Z]+)[.]([_a-zA-Z]+)\s*([(])(.+?)([)])/);
        // /\s*at\s*([_a-zA-Z]+)[.]([<>_a-zA-Z]+)\s*(?<=[(])(.+?)(?=[)])/ にすると失敗?
        let className = match[1];
        let methodName = match[2];
        let url = match[4];
        url = url.split(':');
        let type = url.shift();
        switch (type) {
            case 'http':
            case 'https':
                var domain_fullpath = url.shift();
                var [_, _, domain, ...fullPathName] = domain_fullpath.split('/');
                fullPathName = '/' + fullPathName.join('/');
                var row = url.shift();
                var column = url.shift();
                break;
            case 'file':
                var drive = url.shift();
                var fullPathName = url.shift();
                var row = url.shift();
                var column = url.shift();
                break;
        }
        let fileName = fullPathName.split('/').slice(-1)[0];
        let fullPath = fullPathName.substring(0, fullPathName.length - fileName.length - 1);
        var rc = {
            type: type,
        }
        if (type == 'file') {
            Object.assign(rc, {
                drive: drive,
            });
        } else {
            Object.assign(rc, {
                domain: domain,
            });
        }
        Object.assign(rc, {
            fullPath: fullPath,
            fileName: fileName,
            className: className,
            methodName: methodName,
            row: row,
            column: column,
        });
    }
    return rc;
}
  • 名前を調べる目的の割に長すぎる
  • 関数を呼ぶ度に例外処理を起こすのは実行時間に響きそう
  • chromeのスタック情報に依存したコードなので他ではエラりそう

サンプルでボタンを押すと表示する。

getCurrentLineInfo.jsのSampleClassクラスのexec()を呼び出した場合、
{
 "type": "https",
 "domain": "ssiscirine.iobb.net",
 "fullPath": "/sample/stack",
 "fileName": "getCurrentLineInfo.js",
 "className": "SampleClass",
 "methodName": "exec",
 "row": "5",
 "column": "12"
}
getCurrentLineInfo.jsのgetCurrentLineInfo()を直接呼び出した場合、
{
 "type": "https",
 "domain": "ssiscirine.iobb.net",
 "fullPath": "/sample/stack",
 "fileName": "stack.html",
 "className": "HTMLButtonElement",
 "methodName": "<anonymous>",
 "row": "14",
 "column": "43"
}

FireFoxではクラス名は無いけどメソッド名(関数名?)まで取れるのでサンプルの方は対応している。

HTMLのscriptやonclickからgetCurrentLineInfo()を直接呼び出した場合は行列位置は正しいので使えるけど、他は当てできないね。

それにしても

out.innerText = JSON.stringify(getCurrentLineInfo(),null," ");  ※" "は全角1文字

と、インデントを指定すると、改行もしてくれるので読みやすい。※”\t”も良いらしい。




コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA