call by reference in javascript
Tue, 13 Nov 2007 11:26:42 +0800最近試做了一個csv/xml雙向轉檔的jscript(用到WSH)。為了提高程式的效率,所以嘗試了幾種方法,發現透過陣列的元素,或是物件的屬性,是可以達到call by reference的目的,但是直接把物件傳入函數,對物件本身的一些操作是沒有效果的。
以下是沒有效果的例子:
var a = "a test"; alert(a); test(a); alert(a); function test(str) { str += " more"; alert(str); }
執行上例會依序跳出"a test"、"a test more"、"a test"三個alert對話框,在執行完test函數後,變數a(String物件的instance)並沒有改變。
但是不要以為完全做不到call by reference的效果,其實利用物件屬性或是陣列,可以達到目的。以下是物件屬性的例子:
var a = {"b":"a test"}; alert(a.b); test(a); alert(a.b); function test(obj) { obj.b += " more"; alert(obj.b); }
執行上例,會依序跳出"a test"、"a test more"、"a test more"三個alert對話框,可見傳入的物件屬性真的被改變了,可以達到call by reference的效果。
使用陣列的例子:
var a = ["a test"]; alert(a[0]); test(a); alert(a[0]); function test (arr) { arr[0] += " more"; alert(arr[0]); }
另外,使用物件的方法對物件進行操作,對於用call by reference是否有效呢?試試看:
var a = []; alert(a.length); test(a); alert(a.length); function test(arr) { arr.push("a test"); }
在test函數中對傳入的陣列用push方法增加元素,可以成功進行。執行上例會跳出"0"、"1"兩個對話框,表示陣列元素增加了。
另一個可以操作的例子是Date物件:
var a = new Date(); alert(a.getTime()); test(a); alert(a.getTime()); function test(date) { date.setTime((new Date()).getTime()); }
透過setTime方法,在test函數就可以改變傳入的Date物件代表的時間。
使用者自訂的物件也有類似的效果:
var a1 = new a(); alert(a1.b); test(a1); alert(a1.b); function a () { this.b = "a test"; this.appendB = function (str) { this.b += str; } } function test (obj) { obj.appendB(" more"); }
總結一下。傳入物件給函數操作時,如果操作的對象是物件本身(的primitive value?),不會有call by reference的效果,但是透過物件的方法或屬性來操作,則有call by reference效果。
(至於轉檔程式.....其實算是失敗,倒不是不能跑,而是用自己寫的node物件來產生xml,我要轉的檔案會產生兩萬個樹狀的nodes,處理起來實在太慢,只好改成用直接產生xml內容的方式做,但是這樣就不能因應xml結構的改變。也許改用flyweight來寫會好一點,有空再來試試。)