2009-08-20 16 views
33

Voglio creare una stringa e passarla per riferimento in modo tale da poter modificare una singola variabile e farla propagare a qualsiasi altro oggetto che la fa riferimento.Passare una stringa per riferimento in Javascript

Prendete questo esempio:

function Report(a, b) { 
    this.ShowMe = function() { alert(a + " of " + b); } 
} 

var metric = new String("count"); 
var a = new Report(metric, "a"); 
var b = new Report(metric, "b"); 
var c = new Report(metric, "c"); 
a.ShowMe(); // outputs: "count of a"; 
b.ShowMe(); // outputs: "count of b"; 
c.ShowMe(); // outputs: "count of c"; 

Voglio essere in grado di avere questo accada:

var metric = new String("count"); 
var a = new Report(metric, "a"); 
var b = new Report(metric, "b"); 
var c = new Report(metric, "c"); 
a.ShowMe(); // outputs: "count of a"; 
metric = new String("avg"); 
b.ShowMe(); // outputs: "avg of b"; 
c.ShowMe(); // outputs: "avg of c"; 

Perché non funziona?

Il MDC reference on strings indica che la metrica è un oggetto.

Ho provato questo, che non è quello che voglio, ma è molto vicino:

var metric = {toString:function(){ return "count";}}; 
var a = new Report(metric, "a"); 
var b = new Report(metric, "b"); 
var c = new Report(metric, "c"); 
a.ShowMe(); // outputs: "count of a"; 
metric.toString = function(){ return "avg";}; // notice I had to change the function 
b.ShowMe(); // outputs: "avg of b"; 
c.ShowMe(); // outputs: "avg of c"; 

alert(String(metric).charAt(1)); // notice I had to use the String constructor 
// I want to be able to call this: 
// metric.charAt(1) 

I punti importanti qui:

  1. voglio essere in grado di utilizzare metrica come se fosse un normale oggetto stringa
  2. Voglio che ogni rapporto faccia riferimento allo stesso oggetto.

risposta

45

stringhe in Javascript sono già passati "per riferimento" - chiamando una procedura con una stringa non comporta copiare il contenuto della stringa. Ci sono due problemi a portata di mano:

  • Le stringhe sono immutabili. A differenza delle stringhe C++, una volta creata una stringa JavaScript non può essere modificata.
  • In JavaScript, le variabili non sono assegnate in modo statico agli slot come in C++. Nel tuo codice, metric è un'etichetta che si applica a due variabili stringa completamente separate.

Ecco un modo per ottenere ciò che si vuole, utilizzando le chiusure per implementare scoping dinamico metric:

function Report(a, b) { 
    this.ShowMe = function() { alert(a() + " of " + b); } 
} 

var metric = "count"; 
var metric_fnc = function() { return metric; } 
var a = new Report(metric_fnc, "a"); 
var b = new Report(metric_fnc, "b"); 
a.ShowMe(); // outputs: "count of a"; 
metric = "avg"; 
b.ShowMe(); // outputs: "avg of b"; 
+2

Ben fatto. Mi piace il meglio perché all'interno di Report, posso lavorare con la stringa con un minimo di disordine nella sorgente, cioè a(). CharAt (1) è molto più bello rispetto a String (a) .charAt (1) –

+1

"Una chiusura è un blocco di codice che può essere referenziato (e passato in giro) con accesso alle variabili dell'ambito che lo racchiude. " da http://stackoverflow.com/a/5444581/483588 –

+0

Questo non dimostra il passaggio per valore. Quello che sta facendo è semplicemente cambiare il valore della metrica, ovviamente registrerà il nuovo valore! var obj = { a: "a" }; var b = obj.a; console.log (obj.a); // a b = "b"; console.log (obj.a); // a – user1769128

10

Chiusura?

var metric = new function() { 
    var _value = "count"; 

    this.setValue = function(s) { _value = s; }; 
    this.toString = function() { return _value; }; 
}; 

// snip ... 
a.ShowMe(); 

metric.setValue("avg"); 
b.ShowMe(); 
c.ShowMe(); 

o rendere un po 'più generico e performante:

function RefString(s) { 
    this.value = s; 
} 

RefString.prototype.toString = function() { return this.value; } 
RefString.prototype.charAt = String.prototype.charAt; 

var metric = new RefString("count"); 

// snip ... 

a.ShowMe(); 

metric.value = "avg"; 
b.ShowMe(); 
c.ShowMe(); 

Se non si chiude sulla variabile stringa desiderata, quindi suppongo l'unico altro modo sarebbe quello di modificare la funzione ShowMe , come nella risposta di @John Millikin o re-architetto del codice base.

+1

+1, molto elegante – orip

+0

Bello. Ma volevo evitare un setter ... e non si adatta bene alla chiamata di tutti i metodi di una stringa nativa come charAt senza impostarli manualmente. –

25

È possibile avvolgere la stringa in un oggetto e modificare il campo in cui è memorizzata la stringa. Questo è simile a quello che si sta facendo solo nell'ultimo esempio senza dover modificare le funzioni.

var metric = { str : "count" } 
metric.str = "avg"; 

Ora metric.str conterrà "avg"

+0

Ora questa era la risposta che avevo immaginato quando ero andato su questa pagina. È più o meno la migliore stenografia della "Chiusura?" rispondi anche in questa lista. http://www.w3schools.com/js/js_objects.asp –

+0

Non una chiusura (di per sé) ma la metrica è un oggetto che agisce come i desideri dell'OP: solo la rovina è un riferimento di proprietà extra. Le stringhe JavaScript sono immutabili ma l'oggetto metrico è mutabile e questo oggetto metrico fornisce un livello di riferimento indiretto in modo tale che il riferimento all'oggetto metrico possa essere condiviso. –

0

In JavaScript, le stringhe sono immutabili. Non è possibile modificare la stringa stessa delle istanze dello Report.

la soluzione funziona, ma questo può essere più semplice:

function Report(a, b) { 
    this.showMe = function() { alert(a.str + " of " + b); } 
} 

var metric = {}; 
metric.str = "count"; 

a.Showme(); 
metric.str = "avg"; 
b.ShowMe(); 
3

Se si passa la variabile come un oggetto che funzionerà, dato che gli oggetti vengono passati per riferimento in Javascript.

http://sirdarckcat.blogspot.com/2007/07/passing-reference-to-javascript.html

function modifyVar(obj,newVal){ 
obj.value=newVal; 
} 
var m={value: 1}; 
alert(x); 
modifyVar("x",321); 
alert(x); 
+0

Sì, è quello che mostra il mio ultimo esempio. È un oggetto che sovrascrive la funzione object.toString. –

+0

un uso più generale sarebbe 'function modifyVar (parent, obj, newValue) {parent [obj] = newValue; } '... usa la finestra? se non ci sono altri genitori – technosaurus

0

Jsfiddle: https://jsfiddle.net/ncwhmty7/1/

Entrambe le primitive di stringa (String letterale) e oggetti String sono immutabili . Ciò significa che qualsiasi modifica al contenuto di una variabile di stringa mentre si è nella funzione è completamente separata da qualsiasi cosa avvenga al di fuori della funzione. Ci sono un paio di opzioni per superare questo:

1. Tornando il valore della funzione modificata formare la funzione

function concatenateString(stringA, stringB) { 
    return stringA + stringB; 
} 
alert(concatenateString("Hi", " there")); 

2. Per convertire la variabile stringa in un vero e proprio oggetto

function modifyVar(stringA, stringB) { 
    var result = stringA + stringB; 
    stringA.valueOf = stringA.toSource = stringA.toString = function() { 
     return result; 
    }; 
} 
var stringA = Object('HI'); 
modifyVar(stringA, ' there'); 
alert(stringA); 
Problemi correlati