2009-08-20 81 views
33

我想要创建一个字符串并通过引用传递它,以便我可以更改单个变量并将其传播给引用它的任何其他对象。在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 reference on strings表示度量标准是一个对象。

我已经试过这,这不是我想要的,但很接近:

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. 我希望每个报告引用同一个对象。

回答

45

字符串在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"; 
+2

做得很好。我喜欢这是最好的,因为在报告中,我可以在源代码中使用最少的混乱字符串,即a()。charAt(1)比String(a).charAt(1) – 2009-08-20 20:58:12

+1

更漂亮“闭包是可以通过访问封闭范围的变量来引用(并传递)的代码块。“从http://stackoverflow.com/a/5444581/483588 – 2012-12-22 18:09:00

+0

这并不表明价值传递。这是做什么只是改变度量值,当然它会记录新的价值! var obj = { a:“a” }; var b = obj.a; console.log(obj.a); // a b =“b”; console.log(obj.a); // 一个 – user1769128 2015-06-04 16:04:12

10

关闭?

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的回答或重新构建代码库一样。

+1

+1,非常高雅 – orip 2009-08-20 20:36:26

+0

不错。但是我想避免使用setter ...并且它不能很好地调用像charAt这样的本地String的方法,而无需手动设置它们。 – 2009-08-20 21:00:58

25

您可以将字符串包装在一个对象中,并修改字符串存储的字段。 这与您仅在上一个示例中进行的操作类似,无需更改功能。现在

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

metric.str将包含 “平均”

+0

现在这是我进入这个页面时的图片。这或多或少是“封闭”的最佳缩写?也在这个列表中回答。 http://www.w3schools.com/js/js_objects.asp – 2013-03-28 17:45:40

+0

不是闭包(本身),但度量是一个对象,行为像OP的愿望 - 只有倒台是额外的属性参考。 JavaScript字符串是不可变的,但是度量对象是可变的,而且这个度量对象提供了一个间接级别,以便可以共享度量对象引用。 – 2015-05-06 14:52:11

0

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

如果您传递变量作为对象,将工作,因为对象是通过在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

是的,这就是我最后一个例子所显示的。它是覆盖object.toString函数的对象。 – 2009-08-20 21:01:52

+0

更常用的用法是'function modifyVar(parent,obj,newValue){parent [obj] = newValue; }'...使用窗口?如果没有其他父母 – technosaurus 2014-07-30 05:58:41

0

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

两个字符串原语(字符串文字)和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);