Given an instance of Backbone model, how can I know the "class" (so to speak) of this instance ?
For instance:
class Car extends Backbone.Model
mycar = new Car()
And what I need is:
mycar.modelName # => 'Car'
Given an instance of Backbone model, how can I know the "class" (so to speak) of this instance ?
For instance:
class Car extends Backbone.Model
mycar = new Car()
And what I need is:
mycar.modelName # => 'Car'
It's problematic in general, I think. I was going to suggest some of the options mentioned here ( How do I get the name of an object's type in JavaScript? ) but I was having issues with the first option. You could always extend all your models to have a function that returned a "name" for the model, but I can understand why you might find that less than satisfactory.
I tried Mitch's suggestion but in Chrome, model.constructor.name is always ""
for me.
I chose instead to use a convention. I now create a class property using the second param of extend that works as follows:
directory.models.SomeModel = Backbone.Model.extend({
// usual model instance stuff
}, {
modelType: "SomeModel" // class property
});
I found that I can always get what I want like this:
var mt = model.constructor.modelType;
As of writing you can get a model's class name by doing the following:
model.constructor.name
This works for me in the Chrome browser.
This is already resolved in all browsers except for IE, but a polyfill is easy to make. The answer is Function.name
:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
Definitely take advantage of this! In ES6 classes, a constructor's Function.name is the class name, so in ES6:
class Car { /*...*/ }
var c = new Car();
console.log(c.constructor.name); // "Car"
In current ES5, not all libraries take advantage of this. Backbone, for example, does not. :( Backbone constructors are anonymous functions, so
var m = new Backbone.Model();
console.log(m.constructor.name); // "undefined" :(
unfortunately. Like other's have said, if you're using Backbone, you'll have to make your own naming system.
Here's a polyfill for 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;
}
});
}
You can query the inheritance tree (aka prototype chain) for your object instance like this:
object.__proto__.__proto__.__proto__
You can see what is available. Any type name property will have to be added by you to each view and/or model manually. This is the cleanest way to go. I recommend this. Simply add 'className: "MyCompany.MyProject.MyArea.MyView"' to each of your views and/or models.
If you don't add a className property to your objects, there is a slightly hacky way to still get it (eg for debug output purposes):
Assuming you do something like: "MyCompany.MyProject.MyArea.MyView = Backbone.View.extend({" the view/model class name is in a global namespace var name. From the object instance we cannot reach that global var name. So while not really ideal, the best we can do is traverse the namespace looking for the 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);
Ideally you are using a namespace for your types other than "window". That makes it much cleaner and easier to traverse. You simply replace "window" with the base of your namespace and pass in the desired prefix if you want it prefixed properly. You can also remove a couple lines like the try..catch and the if..continue.
findBackboneClassName(MyCompany.MyProject, myBackboneViewInstance, "MyCompany.MyProject");
The trick of getting class name from objectInstance.constructor does not work for backbone because of the way it does inheritance. All ctors look the same for me: "function () { return parent.apply(this, arguments); }".