2009-08-20 19 views
33

Ich möchte eine Zeichenfolge erstellen und übergeben Sie über Verweis, so dass ich eine einzelne Variable ändern und diese auf jedes andere Objekt, das es referenzieren kann.Übergeben Sie eine Zeichenfolge durch Verweis in Javascript

Nehmen Sie dieses Beispiel:

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"; 

Ich möchte in der Lage sein, dies zu haben:

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"; 

Warum funktioniert das nicht?

Die MDC reference on strings sagt metric ist ein Objekt.

Ich habe das versucht, was nicht, was ich will, ist aber ganz in der Nähe:

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) 

Die wichtigen Punkte hier:

  1. Ich möchte Metrik verwenden, um der Lage sein, wie es ist ein normales String-Objekt
  2. Ich möchte, dass jeder Bericht auf das gleiche Objekt verweisen.

Antwort

45

Strings in Javascript sind bereits bestanden "by reference" - ein Verfahren mit einem String-Aufruf beinhaltet nicht den Inhalt der Zeichenfolge zu kopieren. Es gibt zwei Probleme zur Hand:

  • Strings sind unveränderlich. Im Gegensatz zu C++ - Zeichenfolgen kann eine einmal erstellte JavaScript-Zeichenfolge nicht geändert werden.
  • In JavaScript werden Variablen nicht wie in C++ statisch zugewiesen. In Ihrem Code ist metric eine Bezeichnung, die für zwei völlig separate String-Variablen gilt.

Hier ist ein Weg, um zu erreichen, was Sie wollen, Verschlüsse mit dynamischem Scoping von metric zu implementieren:

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

Schön gemacht. Ich mag das am besten, weil ich innerhalb von Report mit der Zeichenkette mit minimaler Unordnung in der Quelle arbeiten kann, dh a(). CharAt (1) ist viel hübscher gegen Zeichenkette (a) .charAt (1) –

+1

"Eine Schließung ist a Code-Block, der referenziert werden kann (und weitergegeben werden kann) mit Zugriff auf die Variablen des umschließenden Bereichs. " von http://stackoverflow.com/a/5444581/483588 –

+0

Dies zeigt nicht den Wert als bestanden. Was dies tut, ist einfach den Messwert zu ändern, natürlich wird der neue Wert protokolliert! var obj = { a: "a" }; var b = obj.a; console.log (obj.a); // a b = "b"; console.log (obj.a); // ein – user1769128

10

Verschluss?

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(); 

oder macht es ein wenig mehr Generika und performant:

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(); 

Wenn Sie auf den gewünschten String-Variable nicht schließen, dann nehme ich die einzige andere Möglichkeit, die ShowMe Funktion ändern würde wie in @John Millikins Antwort oder re-architect die Codebasis.

+1

+1, sehr elegant – orip

+0

Nizza. Aber ich wollte einen Setter vermeiden ... und er skaliert nicht gut mit dem Aufruf aller nativen String-Methoden wie charAt, ohne sie manuell einzurichten. –

25

Sie können die Zeichenfolge in ein Objekt einfügen und das Feld ändern, in dem die Zeichenfolge gespeichert ist. Dies ist ähnlich wie im letzten Beispiel, ohne dass Sie die Funktionen ändern müssen.

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

Jetzt enthält metric.str "avg"

+0

Dies war die Antwort, die ich mir vorgestellt hatte, als ich auf diese Seite gegangen bin. Es ist mehr oder weniger die beste Kurzschrift für den "Closure?" antworte auch in dieser Liste. http://www.w3schools.com/js/js_objects.asp –

+0

Nicht eine Schließung (per se), aber Metrik ist ein Objekt, das sich wie OP Wünsche - nur Untergang ist zusätzliche Eigenschaft Referenz. JavaScript-Zeichenfolgen sind unveränderlich, aber das metrische Objekt ist änderbar, und dieses Metrikobjekt stellt eine Dereferenzierungsebene bereit, sodass die Metrikobjektreferenz gemeinsam genutzt werden kann. –

0

In JavaScript sind Strings unveränderlich. Sie können die Zeichenfolge selbst nicht ändern, wenn die Report Instanzen ein Handle haben.

Ihre Lösung funktioniert, aber dies einfacher sein:

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

Wenn Sie die Variable als ein Objekt übergeben, es wird funktionieren, da Objekte durch Bezugnahme in Javascript übergeben werden.

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

Ja, das zeigt mein letztes Beispiel. Es ist ein Objekt, das die Funktion object.toString überschreibt. –

+0

eine allgemeinere Verwendung wäre 'Funktion ModifyVar (Eltern, Obj, NewValue) {Eltern [Obj] = NewValue; } '... Fenster benutzen? wenn es kein anderes Elternteil gibt – technosaurus

0

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

Beide String Primitiven (String Literal) und String-Objekte sind unveränderlich . Dies bedeutet, dass alle Änderungen an dem Inhalt einer String-Variablen während der Funktion vollständig von allem, was außerhalb der Funktion geschieht, getrennt sind. Es gibt mehrere Möglichkeiten, dies zu überwinden:

1. Rückkehr der modifizierte Funktionswert

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

2. Um die String-Variable zu einem echten Objekt

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); 
wandeln die Funktion bilden
Verwandte Themen