2010-12-31 12 views
8

Ciao c'è un modo per sovraccaricare l'operatore '.' (Punto) e [] in javascript. cioè se dico obj.Name o obj ['Name'] dovrebbe chiamare un metodo comune nella classe obj passando Nome come argomento. Il tipo simile di funzionalità disponibile in Python usando il metodo delle proprietà. Ma qui voglio che il ". Nome" sia passato come argomento al metodo comune.sovraccarico Javascript dot

come questo ..

function Data(){ 
    this.getValue(name){ 
     return '...' 
    } 
} 

data = new Data() 
name = data.Name 
name = data['Name'] 
//both should call data.getValue() 
+0

Cordiali saluti, le cose sono cambiate da quando la questione è stato chiesto. Ho [aggiornato la mia risposta] (http://stackoverflow.com/a/4569315/157247). –

risposta

1

No, non è possibile sovraccaricare o sostituirla in JavaScript. Vorrei avere una risposta più esauriente/informativa per te ... ma non è possibile, suppongo che non ci sia mai stato bisogno di vedere aggiungere l'abilità.

+0

@ T.J. - fidati di me, un * molto * più del mio tempo sarà occupato * molto * presto;) –

12

risposta nel 2010: (vedi sotto per un aggiornamento del 2013)

No, non si può reindirizzare le ricerche di nomi di proprietà per la propria funzione.

Tuttavia, come da ECMAScript5, è possibile definire le proprietà con "getter" e "setter". Questa è una nuova funzionalità che non è ancora ampiamente supportata, ma quando lo è, farà qualcosa di simile vagamente. Questo è coperto in un paio di parti di the spec. Quindi, se hai definito tutte le proprietà in questo modo e poi hai inviato la richiesta effettiva alla tua funzione centrale getValue, ti ritroverai in gran parte ciò che volevi. Un giorno. :-) Tranne che non chiamerà lo getValue per una proprietà che non esiste.


risposta nel 2013:

Questo sta per cambiare presto (e already has per up-to-date gli utenti di Firefox): ECMAScript 6 ° edizione avrà proxy. Sono definiti nello draft specification e anche nello this page (ma le bozze delle specifiche hanno la precedenza).

I proxy consentono di creare oggetti che sono veri proxy (facciate) per altri oggetti. Ecco un semplice esempio che trasforma tutti i valori di proprietà che sono stringhe a tutti i tappi sul recupero:

var original = {"foo": "bar"}; 
var proxy = new Proxy(original, { 
    get: function(target, name, receiver) { 
     var rv = target[name]; 
     if (typeof rv === "string") { 
      rv = rv.toUpperCase(); 
     } 
     return rv; 
    } 
}); 

console.log("original.foo = " + original.foo); // "bar" 
console.log("proxy.foo = " + proxy.foo);  // "BAR" 

Live Example | Source

Le operazioni su cui non si esegue l'override hanno il loro comportamento predefinito. In quanto sopra, tutto ciò che sovrascriviamo è get, ma c'è un intero elenco di operazioni che è possibile collegare.

Nella lista argomenti della funzione di get gestore:

  • target è l'oggetto proxy (original, nel nostro caso).
  • name è (ovviamente) il nome della proprietà da recuperare.
  • receiver è il proxy stesso o qualcosa che eredita da esso.Nel nostro caso, ===proxy, ma se è stato utilizzato come prototipo, receiver potrebbe essere un oggetto discendente, quindi è sulla firma della funzione (ma alla fine, quindi è facile lasciarlo spento se, come con il nostro esempio sopra, in realtà non lo usi).

Questo consente di creare un oggetto con il catch-all getter e setter funzione che si desidera:

var obj = new Proxy({}, { 
    get: function(target, name) { 
     if (!(name in target)) { 
      console.log("Getting non-existant property '" + name + "'"); 
      return undefined; 
     } 
     return target[name]; 
    }, 
    set: function(target, name, value) { 
     if (!(name in target)) { 
      console.log("Setting non-existant property '" + name + "', initial value: " + value); 
     } 
     target[name] = value; 
    } 
}); 

console.log("[before] obj.foo = " + obj.foo); 
obj.foo = "bar"; 
console.log("[after] obj.foo = " + obj.foo); 

Live Example | Source(Si noti come ho lasciato receiver disattivare le funzioni, dal momento che non lo usiamo receiver è un quarto arg opzionale set..)

L'uscita di quanto sopra è:

Getting non-existant property 'foo' 
[before] obj.foo = undefined 
Setting non-existant property 'foo', initial value: bar 
[after] obj.foo = bar

Nota come otteniamo il messaggio "inesistente" quando proviamo a recuperare foo quando ancora non esiste, e ancora quando lo creiamo, ma non successivamente.

+0

Questo ragazzo. Mi piace questo ragazzo e le sue informazioni. – wootscootinboogie

+0

@wootscootinboogie: Grazie. Cordiali saluti, ho notato che la risposta non era aggiornata e l'ho appena aggiornata. –

+2

Questo ragazzo. E i suoi aggiornamenti. Mi piace questo ragazzo e i suoi aggiornamenti. – jpaugh

1

Nelle versioni JS recenti, esiste effettivamente qualcosa di simile a properties di Python.

Vedere anche domanda Javascript getters and setters for dummies?

Può essere abbastanza per voi, anche se Python è ancora modo più flessibile e compatto.

+0

Questi non sono gli stessi, sono getter e setter * per una proprietà *, non operano su alcuna proprietà. –

+0

+1, ma è molto specifico per l'implementazione ed è stato superato dalla specifica ECMAScript5, che consente di farlo in un modo * completamente * diverso. Quindi il supporto per quella sintassi (che era * terribile *) non si è mai veramente diffuso, e ora sicuramente non lo sarà. Ma ancora, per l'uso in un paio di browser, è una possibilità. –

+0

@Nick: vero, ma l'autore potrebbe quindi rimandare alla funzione centrale 'getValue'. Ma solo per le proprietà * definite *, niente di carino per tutti quelli indefiniti. –

0

Come altri hanno affermato, questo è impossibile in quanto ECMAscript non è possibile per il sovraccarico dell'operatore.

Se si ha realmente bisogno di fare questo allora vorrei usare un po 'di pre-elaborazione per convertire le parti di codice (e solo quelle che hanno davvero bisogno di essere strumentate come questo) in codice strumentato.

Questo potrebbe essere fatto facilmente con un po 'regexp come questo

var a= "var a = b.c['foo']" // get this via xhr or something 
var re = /(\[(.*)\])|(\.([\w\d]+)\b)/g; 

var b = a.replace(re, function(m){ 
    return ".get('" + m.replace(/[[\].'\"]/g,"") + "')"; 
}); 
b; // "var a = b.get('c').get('foo')" 

eval(b);