2010-04-19 14 views
13

Per esempio questo codice:C'è un modo per catturare un tentativo di accedere a una proprietà o un metodo inesistente?

function stuff() { 
    this.onlyMethod = function() { 
    return something; 
    } 
} 

// some error is thrown 
stuff().nonExistant(); 

Esiste un modo per fare qualcosa come PHP di __call come un ripiego da dentro l'oggetto?

function stuff() { 
    this.onlyMethod = function() { 
    return something; 
    } 
    // "catcher" function 
    this.__call__ = function (name, params) { 
    alert(name + " can't be called."); 
    } 
} 

// would then raise the alert "nonExistant can't be called". 
stuff().nonExistant(); 

Forse ti spiego un po 'di più quello che sto facendo.

L'oggetto contiene un altro oggetto, che ha metodi che dovrebbero essere accessibili direttamente attraverso questo oggetto. Ma questi metodi sono diversi per ogni oggetto, quindi non posso solo indirizzarli, devo essere in grado di chiamarli dinamicamente.

So che potrei semplicemente rendere l'oggetto al suo interno una proprietà dell'oggetto principale stuff.obj.existant(), ma mi chiedo solo se potrei evitarlo, poiché l'oggetto principale è una specie di wrapper che aggiunge solo alcune funzionalità temporaneamente (e rende più facile l'accesso all'oggetto allo stesso tempo).

+2

Non puoi usare try catch? O mi manca qualcosa? – Bipul

+0

deve avvenire all'interno della funzione. –

+0

Aggiungo che nelle versioni più recenti di JS/ES, ci sono in effetti meta-metodi getter e setter. –

risposta

9

C'è un modo per definire un gestore generico per chiamate su metodi inesistenti, ma non è standard. Acquista il per Firefox. Ti consente di indirizzare le chiamate a metodi indefiniti in modo dinamico. Sembra che v8 sia anche getting support per questo.

Per utilizzarlo, definire questo metodo su qualsiasi oggetto:

var a = {}; 

a.__noSuchMethod__ = function(name, args) { 
    console.log("method %s does not exist", name); 
}; 

a.doSomething(); // logs "method doSomething does not exist" 

Tuttavia, se si desidera un metodo di cross-browser, quindi semplici blocchi try-catch, se la strada da percorrere:

try { 
    a.doSomething(); 
} 
catch(e) { 
    // do something 
} 

Se non si desidera scrivere try-catch in tutto il codice, è possibile aggiungere un wrapper all'oggetto principale attraverso il quale tutte le chiamate di funzione vengono instradate.

function main() { 
    this.call = function(name, args) { 
     if(this[name] && typeof this[name] == 'function') { 
      this[name].call(args); 
     } 
     else { 
      // handle non-existant method 
     } 
    }, 
    this.a = function() { 
     alert("a"); 
    } 
} 

var object = new main(); 
object.call('a') // alerts "a" 
object.call('garbage') // goes into error-handling code 
+0

grazie mille! ora ho qualcosa su cui lavorare. :) –

+0

trycatch non funziona perché taglia il flusso del codice utente ("Come riprendere l'operazione?") E in secondo luogo, non c'è modo di accedere all'oggetto dal gestore catch. – Pacerier

2

È inoltre possibile verificare se il metodo esiste.

if(a['your_method_that_doesnt_exist']===undefined){ 
//method doesn't exist 
} 
1

Sembra che tu conosca la strada intorno a JS. Purtroppo, non conosco questa funzionalità nella lingua e sono abbastanza sicuro che non esista. La mia opzione migliore, secondo me, è utilizzare un'interfaccia uniforme e estenderla, oppure estendere i prototipi da cui i tuoi oggetti ereditano (quindi puoi usare instanceof prima di andare avanti con la chiamata al metodo) o usare l'operatore un po 'ingombrante' & '&' al fine di evitare l'accesso di proprietà inesistenti/metodi:

obj.methodName && obj.methodName(art1,arg2,...); 

è anche possibile estendere il prototipo oggetto con suggerimento di Anurag ('call').

9

Bene, sembra che con armonia (ES6), ci sarà un modo, ed è più complicato rispetto al modo in cui altri programing languages farlo. Fondamentalmente, essa comporta l'uso Proxy oggetto incorporato per creare un involucro sull'oggetto, e modificare il comportamento predefinito modo suo implementato su di esso:

obj = new Proxy({}, 
     { get : function(target, prop) 
      { 
       if(target[prop] === undefined) 
        return function() { 
         console.log('an otherwise undefined function!!'); 
        }; 
       else 
        return target[prop]; 
      } 
     }); 
obj.f()  ///'an otherwise undefined function!!' 
obj.l = function() {console.log(45);}; 
obj.l();  ///45 

Proxy inoltrerà tutti i metodi non gestiti da gestori nel normale oggetto. Quindi sarà come se non fosse lì, e dal proxy è possibile modificare l'obiettivo.Ci sono anche più gestori, anche alcuni per modificare il prototipo di ottenere e setter per qualsiasi accesso di proprietà sì !.

Come puoi immaginare, questo non è supportata in tutti i browser in questo momento, ma in Firefox si può giocare con l'interfaccia Proxy abbastanza facile, basta andare al MDN docs

E mi renderebbe più felice se il gestito per aggiungere dello zucchero sintattico su questo, ma comunque, è bello avere questo tipo di potere in un linguaggio già potente. Buona giornata! :)

PD: Non ho copiato l'ingresso di rosettacode js, l'ho aggiornato.

+0

Ma questo è inutile in quanto non funziona sull'oggetto obiettivo stesso, ma su un oggetto nuovo di zecca. In altre parole, non è possibile utilizzarlo per catturare l'accesso alle proprietà di 'Array'. – Pacerier

Problemi correlati