2012-03-13 1 views
26

Data un'istanza del modello Backbone, come posso conoscere la "classe" (per così dire) di questa istanza?Ottieni un modello/nome classe dell'istanza del modello Backbone

Per esempio:

class Car extends Backbone.Model 

mycar = new Car() 

E che cosa ho bisogno è:

mycar.modelName # => 'Car' 
+1

Devi essere più specifico. Un modello potrebbe avere più viste. La vista ha il riferimento .el che AFAIK dovrebbe essere sufficiente, * se stai considerando le viste *. Ma potrebbe non essere quello che stai chiedendo. – JayC

+0

Ah, non importa. Stai parlando a livello di codice. – JayC

+0

Perché hai bisogno del nome di classe? Per creare un nuovo modello dello stesso tipo o per accedere a una funzione di livello di classe o qualcos'altro? La sua domanda interessante – websymphony

risposta

10

E 'problematico, in generale, credo. Stavo per suggerire alcune delle opzioni menzionate qui (How do I get the name of an object's type in JavaScript?) ma stavo avendo problemi con la prima opzione. Potresti sempre estendere tutti i tuoi modelli per avere una funzione che ha restituito un "nome" per il modello, ma posso capire perché potresti trovarlo meno che soddisfacente.

+1

Sono d'accordo, o lo risolvete manualmente come suggerisce @JayC o state parlando di una preoccupazione JS generica molto vecchia ancora non risolta. – fguillen

14

Al momento di scrivere è possibile ottenere il nome di classe di un modello nel modo seguente:

model.constructor.name 

questo funziona per me nel browser Chrome.

+15

Nota che non funzionerà se hai un minificatore come Jammit, il costruttore cambierà dopo il confezionamento. –

23

Ho provato il suggerimento di Mitch ma in Chrome, model.constructor.name è sempre "" per me.

Ho scelto invece di utilizzare una convenzione. Ora creare una proprietà di classe utilizzando la seconda param di estendere che funziona come segue:

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

ho scoperto che posso sempre ottenere ciò che voglio in questo modo:

var mt = model.constructor.modelType; 
0

Questo è già risolto in tutti i browser eccetto IE, ma un polyfill è facile da realizzare. La risposta è Function.name:

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

assolutamente approfittare di questo! Nelle classi ES6, Function.name di un costruttore è il nome della classe, quindi in ES6:

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

Nel corso ES5, non tutte le librerie approfittare di questo. Backbone, per esempio, no. :(costruttori Backbone sono funzioni anonime, così

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

purtroppo. Come altri sono detto, se si sta utilizzando Backbone, dovrete fare il vostro proprio sistema di denominazione.

Ecco un polyfill per la funzione .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

È possibile interrogare l'albero di ereditarietà (aka catena di prototipi) per l'istanza oggetto come questo:

oggetto .__ proto __.__ proto __.__ proto__

È possibile visualizzare ciò che è disponibile. Qualsiasi proprietà del nome del tipo dovrà essere aggiunta dall'utente a ogni vista e/o modello manualmente. Questo è il modo più pulito per andare. Lo raccomando. Aggiungi semplicemente "className:" MyCompany.MyProject.MyArea.MyView "" a ciascuna delle tue visualizzazioni e/o modelli.

Se non si aggiunge una proprietà className agli oggetti, c'è un modo un po 'hacky per ottenere ancora (ad esempio per scopi di output di debug):

Supponendo di fare qualcosa di simile: "MyCompany.MyProject. MyArea.MyView = Backbone.View.extend ({"il nome della classe vista/modello si trova in un nome var globale dello spazio dei nomi. Dall'istanza dell'oggetto non è possibile raggiungere il nome globale var. Quindi, anche se non proprio ideale, il meglio che possiamo fare è attraversare lo spazio dei nomi alla ricerca del 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); 

Idealmente si utilizza uno spazio dei nomi per i tipi diversi da "finestra" Questo rende molto più pulito e più facile da attraversare. Sostituisci semplicemente "finestra" con la base del tuo spazio dei nomi e passa il prefisso desiderato se vuoi che sia prefissato correttamente. Puoi anche rimuovere un paio di linee come try..catch e if..continue.

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

Il trucco di ottenere il nome della classe da objectInstance.constructor non funziona per la spina dorsale a causa del modo in cui funziona l'ereditarietà. Tutti i castori hanno lo stesso aspetto per me: "function() {return parent.apply (this, arguments);}".