2009-08-20 151 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);