Je souhaite créer une chaîne et la transmettre par référence de manière à pouvoir modifier une seule variable et la transmettre à tout autre objet qui la référence.
Prenons cet exemple:
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";
Je veux pouvoir que cela se produise:
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";
Pourquoi ça ne marche pas?
La référence MDC sur les chaînes indique que la métrique est un objet.
J'ai essayé ceci, ce qui n'est pas ce que je veux, mais qui est très proche:
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)
Les points importants ici:
Les chaînes en Javascript sont déjà passées "par référence" - appeler une procédure avec une chaîne n'implique pas de copier le contenu de la chaîne. Il y a deux problèmes à résoudre:
metric
est dans votre code une étiquette qui s'applique à deux variables de chaîne entièrement distinctes.Voici un moyen d’atteindre ce que vous voulez, en utilisant des fermetures pour implémenter la portée dynamique de 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";
Vous pouvez envelopper la chaîne dans un objet et modifier le champ dans lequel la chaîne est stockée dans . Ceci est similaire à ce que vous faites dans le dernier exemple, sans qu'il soit nécessaire de modifier les fonctions.
var metric = { str : "count" }
metric.str = "avg";
Maintenant, metric.str contiendra "avg"
Fermeture?
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();
ou en le rendant un peu plus générique et 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();
Si vous ne fermez pas sur la variable de chaîne souhaitée, alors je suppose que la seule autre solution consisterait à modifier la fonction ShowMe, comme dans la réponse de John Millikin ou à restructurer la base de code.
Si vous transmettez la variable en tant qu’objet, cela fonctionnera, car les objets sont passés par référence en 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);
Jsfiddle: https://jsfiddle.net/ncwhmty7/1/
Les primitives de chaîne (String Literal) et les objets String sont immuables. Cela signifie que les modifications apportées au contenu d'une variable de chaîne dans la fonction sont complètement séparées de tout ce qui se produit en dehors de la fonction. Il existe plusieurs options pour surmonter ceci:
1. Retour de la valeur de la fonction modifiée à partir de la fonction
function concatenateString(stringA, stringB) {
return stringA + stringB;
}
alert(concatenateString("Hi", " there"));
2. Pour convertir la variable chaîne en un véritable objet
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);
Si cette chaîne est une propriété d'un objet, vous pouvez envoyer l'objet et la chaîne de caractères de la propriété:
this.modificationFunction = function(object, stringKey){
object[stringKey] = object[stringKey] + "bla bla bla";
}
myObject.myStringProperty = "She said: ";
this.modificationFunction(myObject, "myStringProperty");
// myObject.myStringProperty is now "She said: bla bla bla";
En JavaScript, les chaînes sont immuables. Vous ne pouvez pas modifier la chaîne elle-même si les instances Report
ont un descripteur.
votre solution fonctionne, mais cela peut être plus simple:
function Report(a, b) {
this.showMe = function() { alert(a.str + " of " + b); }
}
var metric = {};
metric.str = "count";
a.Showme();
metric.str = "avg";
b.ShowMe();