Передать строку по ссылке в Javascript - PullRequest
41 голосов
/ 21 августа 2009

Я хочу создать строку и передать ее по ссылке, чтобы я мог изменить одну переменную и распространить ее на любой другой объект, который ссылается на нее.

Возьмите этот пример:

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. Я хочу использовать метрику , как будто это обычный строковый объект
  2. Я хочу, чтобы каждый отчет ссылался на один и тот же объект.

Ответы [ 7 ]

54 голосов
/ 21 августа 2009

Строки в Javascript уже переданы «по ссылке» - вызов процедуры со строкой не требует копирования содержимого строки. Есть две проблемы под рукой:

  • Строки неизменны. В отличие от строк C ++, после создания строки JavaScript ее нельзя изменить.
  • В JavaScript переменные не являются статически назначаемыми слотами, как в C ++. В вашем коде 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";
32 голосов
/ 21 августа 2009

Вы можете обернуть строку в объект и изменить поле, в котором хранится строка. Это похоже на то, что вы делаете в последнем примере, только без необходимости изменять функции.

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

Теперь metric.str будет содержать «avg»

10 голосов
/ 21 августа 2009

Закрытие

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, как в ответе Джона Милликина, или перестроить кодовую базу.

3 голосов
/ 21 августа 2009

Если вы передадите переменную как объект, она будет работать, поскольку объекты передаются по ссылке в 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);
1 голос
/ 06 февраля 2017

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

Оба строковых примитива (String Literal) и объекты String являются неизменяемыми. Это означает, что любые изменения содержимого строковой переменной в функции полностью отделены от всего, что происходит вне функции. Есть несколько вариантов преодоления этого:

1. Возврат измененного значения функции из функции

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

2. Чтобы преобразовать строковую переменную в истинный объект

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);
0 голосов
/ 16 января 2019

Если эта строка является свойством какого-либо объекта, вы можете отправить объект и 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";
0 голосов
/ 21 августа 2009

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