Передача строки по ссылке в Javascript
Я хочу создать строку и передать ее по ссылке, чтобы я мог изменить одну переменную и распространить ее на любой другой объект, который ссылается на нее.
Возьмем этот пример:
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";
Я хочу, чтобы это произошло:
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";
Почему это не работает?
ссылка MDC на строки говорит, что метрика - это объект.
Я пробовал это, чего я не хочу, но очень близко:
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)
Важные моменты здесь:
- Я хочу использовать метрику как обычный объект строки
- Я хочу, чтобы каждый отчет ссылался на один и тот же объект.
Ответы
Ответ 1
Строки в Javascript уже переданы "по ссылке" - вызов процедуры со строкой не требует копирования содержимого строки. Есть два вопроса:
- Строки неизменяемы. В отличие от строк С++, после создания строки JavaScript она не может быть изменена.
- В JavaScript переменные не являются статически назначенными слотами, как в С++. В вашем коде
metric
- это метка, которая применяется к двум полностью отдельным строковым переменным.
Здесь один из способов добиться того, чего вы хотите, используя затворы для реализации динамического охвата 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
Вы можете обернуть строку в объект и изменить поле, в котором хранится строка.
Это похоже на то, что вы делаете в последнем примере, только без необходимости изменять функции.
var metric = { str : "count" }
metric.str = "avg";
Теперь metric.str будет содержать "avg"
Ответ 3
Закрытие?
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();
или сделать его немного более общим и результативным:
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();
Если вы не закрываете нужную строковую переменную, я полагаю, что единственным способом было бы изменить функцию ShowMe, как в @John Millikin ответить или перепроектировать кодовую базу.
Ответ 4
Если вы передадите переменную как объект, она будет работать, поскольку объекты передаются по ссылке в 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);
Ответ 5
Jsfiddle: https://jsfiddle.net/ncwhmty7/1/
Оба примитива строки (String Literal) и объекты String неизменяемы. Это означает, что любые изменения содержимого строковой переменной во время функции полностью отделены от всего, что происходит вне функции. Есть несколько вариантов преодоления этого:
1. Возвращая значение измененной функции, выполните функцию
function concatenateString(stringA, stringB) {
return stringA + stringB;
}
alert(concatenateString("Hi", " there"));
2. Чтобы преобразовать строковую переменную в true Object
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);
Ответ 6
В JavaScript строки неизменяемы. Вы не можете сами изменить строку, в которой экземпляры Report
имеют дескриптор.
ваше решение работает, но это может быть проще:
function Report(a, b) {
this.showMe = function() { alert(a.str + " of " + b); }
}
var metric = {};
metric.str = "count";
a.Showme();
metric.str = "avg";
b.ShowMe();
Ответ 7
Если эта строка является свойством какого-либо объекта, вы можете отправить объект и stringKey этого свойства:
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";