web-dev-qa-db-ja.com

バックボーンモデルインスタンスのモデル/クラス名を取得する

バックボーンモデルのインスタンスが与えられた場合、このインスタンスの(いわば)「クラス」をどのようにして知ることができますか?

例えば:

class Car extends Backbone.Model

mycar = new Car()

そして私が必要なのは:

mycar.modelName # => 'Car'
27
Blacksad

全般的に問題があると思います。ここで言及したオプションのいくつかを提案するつもりでした( JavaScriptでオブジェクトのタイプの名前を取得するにはどうすればよいですか? )が、最初のオプションで問題が発生していました。常にすべてのモデルを拡張して、モデルの「名前」を返す関数を持たせることもできますが、それが満足できるものではない理由を理解できます。

10
JayC

ミッチの提案を試しましたが、Chromeではmodel.constructor.nameは常に"" 私のために。

代わりに、慣例を使用することにしました。次に、extendの2番目のパラメーターを使用して、次のように機能するクラスプロパティを作成します。

directory.models.SomeModel = Backbone.Model.extend({ 
    //  usual model instance stuff
}, {
    modelType: "SomeModel"   // class property
});

私はいつでもこのようにしたいものを手に入れることができることがわかりました:

var mt = model.constructor.modelType;
23

執筆時点では、次のようにしてモデルのクラス名を取得できます。

model.constructor.name

これは、Chromeブラウザで動作します。

14
Mitch

これはIEを除くすべてのブラウザーで既に解決されていますが、ポリフィルは簡単に作成できます。答えはFunction.name

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

間違いなくこれを活用してください! ES6クラスでは、コンストラクターのFunction.nameがクラス名であるため、ES6では次のようになります。

class Car { /*...*/ }
var c = new Car();
console.log(c.constructor.name); // "Car"

現在のES5では、すべてのライブラリがこれを利用するわけではありません。たとえば、バックボーンにはありません。 :(バックボーンコンストラクタは匿名関数なので、

var m = new Backbone.Model();
console.log(m.constructor.name); // "undefined" :(

残念ながら。他の人が言ったように、バックボーンを使用している場合は、独自のネーミングシステムを作成する必要があります。

Function.nameのポリフィルは次のとおりです。

// Polyfill for Function.name on browsers that do not support it (IE):
// See: http://stackoverflow.com/questions/6903762/function-name-not-supported-in-ie
if (!(function f() {}).name) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var name = this.toString().match(/^\s*function\s*(\S*)\s*\(/)[1];

            // For better performance only parse once, and then cache the
            // result through a new accessor for repeated access.
            Object.defineProperty(this, 'name', { value: name });

            return name;
        }
    });
}
0
trusktr

次のように、オブジェクトインスタンスの継承ツリー(別名プロトタイプチェーン)をクエリできます。

object .__ proto __.__ proto __.__ proto__

何が利用可能かを確認できます。タイプ名のプロパティは、手動で各ビューやモデルに追加する必要があります。これが最もクリーンな方法です。私はこれをお勧めします。 「className: "MyCompany.MyProject.MyArea.MyView"」をビューやモデルに追加するだけです。

オブジェクトにclassNameプロパティを追加しない場合でも、それを取得するための少しハックな方法があります(たとえば、デバッグ出力の目的で)。

「MyCompany.MyProject.MyArea.MyView = Backbone.View.extend({」というようなことをすると、ビュー/モデルクラス名はグローバルネームスペースvar名にあります。オブジェクトインスタンスからは、そのグローバルvar名に到達できません。本当に理想的ではありませんが、私たちができる最善のことは、varを探して名前空間をトラバースすることです。

function findBackboneClassName(ns, object, prefix, depth) {
    prefix = typeof prefix !== 'undefined' ? prefix : "";
    depth = typeof depth !== 'undefined' ? depth : 0;
    if (depth > 5) return null;

    for (i in ns) {
        try { ns[i]; } catch (e) { continue; }
        if (/top|window|document|parent|frames|self|chrome|form|theForm/.test(i)) continue;
        //console.log(">" + prefix + "." + i + " " + typeof(ns[i]));

        if (ns[i] == object.constructor) {
            //console.log("Found:", prefix + "." + i);
            return prefix + "." + i;
        }

        if (typeof (ns[i]) == "object") {
            var r = findBackboneClassName(ns[i], object, prefix + (prefix != "" ? "." : "") + i, depth + 1);
            if (r != null) return r;
        }
    }
    return null;
}
findBackboneClassName(window, myBackboneViewInstance);

理想的には、「ウィンドウ」以外のタイプの名前空間を使用しています。これにより、よりクリーンでトラバースが容易になります。 「ウィンドウ」をネームスペースのベースに置き換えるだけで、適切にプレフィックスを付ける場合は、目的のプレフィックスを渡します。また、try..catchやif..continueなどの数行を削除することもできます。

findBackboneClassName(MyCompany.MyProject, myBackboneViewInstance, "MyCompany.MyProject");

ObjectInstance.constructorからクラス名を取得するトリックは、継承の方法が原因で、バックボーンでは機能しません。私にとって、すべてのアクターは同じように見えます:「function(){return parent.apply(this、arguments);}」。

0
Curtis Yallop