2012-06-06 16 views
21

Qual è il miglior modello di progettazione per ottenere quanto segue (che non funziona)?Javascript: chiamata ai metodi oggetto all'interno dell'oggetto

var obj = (function() { 

    // code defining private variables and methods 

    var _obj = { 
    property: value, 
    method1: function() { 
     // do stuff 
    }, 
    method2: function() { 
     // use property 
     var prop = _obj.property; // obviously doesn't work 
     // call method1 
     obj.method1(); // "obj" not finished being defined yet! 
    } 
    }; 

    // obviously now I could do... 
    var prop = _obj.property; 

    return _obj; 

})(); 

// and I could now do... 
obj.method1(); 

Una variazione che credo dovrebbe funzionare è

var obj = (function() { 

    var property = value, 
     method1 = function() { 
     // do stuff 
     }, 
     method2 = function() { 
     // use property 
     var prop = property; 
     // call method1 
     method1(); 
     }, 
     _obj = { 
     property: property, 
     method1: method1, 
     method2: method2 
     }; 

    return _obj; 

})(); 

Allo stesso modo, come funziona per gli oggetti destinati ad essere creato con l'operatore new? All'interno della funzione di costruzione stessa è possibile scrivere . Ma cosa succede se si desidera mantenere il costruttore piccolo, definendo solo quelle cose che saranno probabilmente personalizzate al momento della creazione e quindi definendo il resto nel prototipo? (Questo sembra essere il modello comune.) Le proprietà/metodi all'interno del prototipo possono interagire in qualche modo?

var MyObj = function(name) { 
    this.name = name; 
}; 

var obj = new MyObj('Bob'); 

MyObj.prototype = { 
    called_often: function() { 
    // lots more code than just the following 
    return document.getElementById('someID').value; 
    }, 

    global_default: 'value', // can be changed, so need to pull value when run 

    does_stuff: function(value) { 
    var str = global_default + value, // can't access global_default on its own 
     input = MyObj.called_often(), // doesn't work; MyObj.prototype.called_often() DOES 
     name = this.name; // 'this' used in the prototype doesn't work 
          // even within a created object 
    return name + input + str; 
    } 
}; 

Sono sicuro che ci sono modi migliori per raggiungere il mio risultato ogni volta che mi imbatto in questo problema. Questo codice non è specifico per la situazione e illustra semplicemente il problema generale. Quindi non sarai in grado di darmi un'alternativa per quelle situazioni specifiche in cui mi imbatto. Ma forse puoi aiutare il mio pensiero generale.

risposta

26

Ebbene, dal primo esempio:

var _obj = { 
    property: value, 
    method1: function() { 
     // do stuff 
    }, 
    method2: function() { 
     // use property 
     var prop = this.property; 
     // call method1 
     this.method1(); 
    } 
    }; 

Questo è ciò che il valore this è per.

Ora, ciò che non è possibile fare è fare riferimento a una proprietà di un oggetto "in costruzione" da altrove nella sintassi letterale dell'oggetto. (È difficile dare un esempio perché non è sintatticamente possibile.) Nei casi in cui si desidera farlo, è necessario uno o più estratti separati.

+0

Avevo pensato che "questo" punta solo all'oggetto se è stato creato con il nuovo + costruttore, o se si usa call/apply. Ma hai ragione, funziona! Apparentemente sono stato confuso per tutto questo tempo. Inoltre, avevo pensato di averlo provato. Ma apparentemente no. –

+0

JavaScript è incredibilmente semplice e incredibilmente complicato allo stesso tempo :-) Si scopre che "questo" è legato al momento in cui viene chiamata una funzione, e questo è quanto; tuttavia questa semplice regola porta a tutti i tipi di dettagli interessanti. – Pointy

+0

Ciao, a punta. Ho lo stesso tipo di problema. Sto usando 'roundslider.js' e sto chiamando una funzione in cui hai scritto cose da fare. Ma è un errore per me. '$ (" cursore # "). RoundSlider ({ modifica: function (evento) { traceEvent() },' }); – locateganesh

9

Indovina cosa? Stai rendendo semplici le cose semplici. La risposta di Pointy è buona, ma la modalità del prototipo è migliore per diversi motivi. Ecco perché sto descrivendo (piuttosto, apportando correzioni) l'ultimo metodo. Check this fiddle.

var MyObj = function(name) { 
    this.name = name; 
}; 

MyObj.prototype = { 
    called_often: function() { 
    // lots more code than just the following 
    return 'VALUE'; //document.getElementById('someID').value; 
    }, 

    global_default: 'value', // can be changed, so need to pull value when run 

    does_stuff: function(value) { 
    var str = this.global_default + value, // can't access global_default on its own 
     input = this.called_often(), // doesn't work; MyObj.prototype.called_often() DOES 
     name = this.name; // 'this' used in the prototype doesn't work 
          // even within a created object 
    return name + input + str; 
    } 
}; 

var obj = new MyObj('Bob'); 
+0

Grazie per aver dedicato del tempo a buttarlo in jsfiddle! Come ho commentato il post sopra, apparentemente ero confuso riguardo alla possibilità di usare "questo" in queste situazioni. (Ovviamente, come ho commentato nella versione del prototipo che "questo non funzionerà".) So per certo che ho provato ad usarlo in un prototipo prima e ho ottenuto un errore. Ora dovrò rivisitare quel codice e vedere cosa stavo effettivamente facendo male, perché ovviamente non era l'uso di "questo"! –

+0

Questa è un'ottima risposta. – Pointy

+1

@Pointy, grazie! ;) –

Problemi correlati