ECMAScript中所有函數的參數都是按值傳遞的,簡單講就是函數外部的值 複製給函數內部的參數,就和把值從一個變數複製到另一個變數一樣。切記訪問變數有按值訪問和按引用訪問,而參數只能按值傳遞。 在向參數傳遞基本類型的值時,被傳遞的值會被覆制給一個局部變數(可以把ECMAScript函數中的參數想象 ...
ECMAScript中所有函數的參數都是按值傳遞的,簡單講就是函數外部的值 複製給函數內部的參數,就和把值從一個變數複製到另一個變數一樣。切記訪問變數有按值訪問和按引用訪問,而參數只能按值傳遞。
在向參數傳遞基本類型的值時,被傳遞的值會被覆制給一個局部變數(可以把ECMAScript函數中的參數想象成局部變數);向參數傳遞引用類型的值時,會把這個值在記憶體中的地址複製給一個局部變數。
實例1:
// 參數是基本類型的值 function add(n){ n += 1; return n; } var num = 2; var result = add(num); alert(num); // 2 alert(result); // 3
在函數內,參數n的值被加上1,但這並不會影響函數外的num變數,參數n與變數num僅僅是具有相同值,但互不相識。如果是按引用傳遞,則變數num的值將變為3.
實例2:
// 參數是對象 function setName(obj){ obj.name = "123"; } var p = new Object(); setName(p); alert(p.name); // "123"
這裡創建了一個對象,並保存在變數p中,當這個對象被傳遞到setName()函數中之後就被覆制給了obj。在函數內,obj和p引用的是同一個對象。也可以說即使這個對象是按值傳遞的,obj也會按引用來訪問同一個對象。所以在函數內為obj添加name屬性後,函數外的p會反映出來,這裡p指向的對象在堆記憶體中只有一個,並且是全局對象。
很多錯誤地認為在局部作用域中修改的對象會在全局作用域中反映出來,就說明是按引用傳遞。為了證明上面例子是按值傳遞,再看下麵的實例3:
function setName(obj){ obj.name = "123"; obj = new Object(); // obj的值變為堆記憶體中一個新的地址,但o變數的值並不受影響 obj.name = "321"; } var p = new Object(); setName(p); alert(p.name); // "123"
這裡與實例2中不同的是給obj重新定義了一個對象,並重新定義了name屬性。如果p是按引用傳遞的,那麼p就會自動被修改為指向name屬性值為“321”的新對象,但實際訪問p.name時,值仍是“123”。這就說明雖然在函數內修改了參數的值,但原始變數的引用不會受影響,保持不變。其實當參數是對象時,按值傳遞時傳遞的就是對象在堆記憶體中的地址 另:當在函數內部重寫obj時,這個變數引用的就是一個局部對象了,而這個局部對象在函數執行完後立即被銷毀。
在Java中也類似,以下是簡單的實例:
public class Demo14 { public static void main(String[] args) throws Exception{ int num = 2; int result = add(num); System.out.println(num); // 2 System.out.println(result); // 3 Obj o = new Obj(); setObjName(o); System.out.println(o.getName()); // 123 } public static int add(int n){ n += 1; return n; } public static void setObjName(Obj obj){ obj.setName("123"); obj = new Obj(); // obj的值變為堆記憶體中一個新的地址,但o變數的值並不受影響 obj.setName("321"); } } class Obj{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }