Подтвердить что ты не робот

Получить экземпляр модели/класс модели Backbone Model

Учитывая экземпляр модели Backbone, как я могу узнать "класс" (так сказать) этого экземпляра?

Например:

class Car extends Backbone.Model

mycar = new Car()

И мне нужно:

mycar.modelName # => 'Car'
4b9b3361

Ответ 1

Это проблематично вообще, я думаю. Я собирался предложить некоторые из упомянутых здесь опций (Как получить имя типа объекта в JavaScript?), но у меня возникли проблемы с первым вариантом. Вы всегда можете расширить все свои модели, чтобы иметь функцию, которая вернула "имя" для модели, но я могу понять, почему вы можете найти это менее чем удовлетворительным.

Ответ 2

Я попробовал предложение Митча, но в Chrome, model.constructor.name всегда "" для меня.

Вместо этого я решил использовать соглашение. Теперь я создаю свойство класса, используя второй параметр расширения, который работает следующим образом:

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

Я обнаружил, что всегда могу получить то, что хочу:

var mt = model.constructor.modelType;

Ответ 3

С момента написания вы можете получить имя класса модели, выполнив следующие действия:

model.constructor.name

Это работает для меня в браузере Chrome.

Ответ 4

Это уже разрешено во всех браузерах, кроме IE, но polyfill легко сделать. Ответ 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" :(

к сожалению. Как и другие, если вы используете Backbone, вам нужно будет создать собственную систему именования.

Здесь polyfill для 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;
        }
    });
}

Ответ 5

Вы можете запросить дерево наследования (aka prototype chain) для вашего экземпляра объекта следующим образом:

объект.__ прото __.__ прото __.__ прото __

Вы можете видеть, что доступно. Любое свойство имени типа должно быть добавлено вами для каждого вида и/или модели вручную. Это самый чистый путь. Я рекомендую это. Просто добавьте "className:" MyCompany.MyProject.MyArea.MyView "к каждому из ваших представлений и/или моделей.

Если вы не добавляете свойство className к своим объектам, есть немного хакерский способ его получить (например, для целей вывода отладки):

Предполагая, что вы делаете что-то вроде: "MyCompany.MyProject.MyArea.MyView = Backbone.View.extend({" имя класса/класса в глобальном имени var names пространства имен ". Из экземпляра объекта мы не можем достичь этого глобального 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 не работает для магистрали из-за того, как он наследует. Все ctors выглядят одинаково для меня: "function() {return parent.apply(this, arguments);}".