JavaScript 參數傳遞與變量復制


        ECMAScript 變量可能包含兩種不同數據類型的值:基本類型值和引用類型值。 基本類型值指的是簡單的數據段,而引用類型值指那些可能由多個值構成的對象。
        5 種基本數據類型: Undefined、 Null、 Boolean、 Number 和 String。 這 5 種基本數據類型是按值訪問的,因為可以操作保存在變量中的實際的值。
        引用類型的值是保存在內存中的對象。與其他語言不同, JavaScript 不允許直接訪問內存中的位置,也就是說不能直接操作對象的內存空間。在操作對象時,實際上是在操作對象的引用而不是實際的對象。為此,引用類型的值是按引用訪問的。
 
動態的屬性
        對於引用類型的值,我們可以為其添加屬性和方法,也可以改變和刪除其屬性和方法。
        對象不被銷毀,設置的屬性和方法,將一直存在。
        不能給基本類型的值設置屬性和方法。
復制變量值
          如果從一個變量向另一個變量復制基本類型的值,會在變量對象上創建一個新值,然后把該值復制 到為新變量分配的位置上。 這兩個變量可以參與任 何操作而不會相互影響。(復制變量的值)
          當從一個變量向另一個變量復制引用類型的值時,同樣也會將存儲在變量對象中的值復制一份放到 為新變量分配的空間中。不同的是,這個值的副本實際上是一個指針,而這個指針指向存儲在堆中的一 個對象。復制操作結束后,兩個變量實際上將引用同一個對象。因此,改變其中一個變量,就會影響另 一個變量。(復制的是引用指針)
傳遞參數
          ECMAScript 中所有函數的參數都是按值傳遞的。也就是說,把函數外部的值復制給函數內部的參 數,就和把值從一個變量復制到另一個變量一樣。
          訪問變量有按值和按引用兩種方式,而參數只能按值傳遞

        在向參數傳遞基本類型的值時,被傳遞的值會被復制給一個局部變量(即命名參數,或者用ECMAScript 的概念來說,就是 arguments 對象中的一個元素)。

 

1
2
3
4
5
6
7
8
function addTen(num){
     num +=10;
     return num;
}
var count = 20;
var result = addTen(count);
alert(count);   //20
alert(result);  //30

        在向參數傳遞引用類型的值時,會把這個值在內存中的地址復制給一個局部變量,因此這個局部變量的變化會反映在函數的外部。傳給函數的是數值的一個引用,函數中對其屬性的修改外部可見,但用新引用覆蓋其則在外部不可見。

1
2
3
4
5
6
function setName(obj){
     obj.name = "staven" ;
}
var person = new Object();
setName(person);
alert(person.name);  //staven

普通賦值
1
2
3
4
var a = 1;
var b = a;   //賦的是a的復制值
b ++;
alert(a);   //"1"   b的修改不影響a
對象賦值
1
2
3
4
var a = [1];
var b = a;     //賦的是a的引用
b[0] ++;
alert(a);  //"2"   b的修改對a也有效
參數傳值傳遞:傳給函數的是數值的一個復制,函數中對其的修改外部不可見
1
2
3
4
5
6
7
8
9
10
11
12
var a = 1;
var b = 2;
function change(a,b) {
   var c = a;
   a = b;      //用新引用覆蓋
   b = c;
   alert(a);   //"2"        
   alert(b);   //"1"
}
change(a,b);
alert(a);   //"1"        
alert(b);   //"2"
傳址的傳遞:傳給函數的是數值的一個引用,函數中對其屬性的修改外部可見,但用新引用覆蓋其則在外部不可見
1
2
3
4
5
6
7
8
9
10
11
12
13
var a = [1, 2, 3];
var b = [5, 6];
function change(a,b) {
   a[0] = 4;    //對其屬性的修改外部可見 
   var c = a;
   a = b;      //用新引用覆蓋
   b = c;
   alert(a);   //"5,6"        
   alert(b);   //"4,2,3"
}
change(a,b);
alert(a);    //"4,2,3"
alert(b);     //"5,6"
          a,b是change函數中的變量,在調用函數時傳遞了a,b的引用賦給了這兩個變量,但是並不能改變全局中的a,b。 因為用新引用覆蓋在外部不可見,因為函數只是拿到了引用 並沒有權力更改引用。
1
2
3
4
5
6
7
8
9
10
11
var a = [1, 2, 3];
var b = [5, 6];
function change() {
   var c = a;
   a[0] = 4;
   a = b;
   b = c;
};
change();
alert(a);   //"5,6"
alert(b);   //"4,2,3"
          又得提到js的塊級作用域了,這個放某些語言里定然是要報未定義錯誤的,因為js沒有塊級作用域,所以它在change里找不到變量a,b就會自覺的到上層去找,所以這里的a,b是全局變量的引用。
 
     傳值的比較比較的是數值 而傳址的比較比較的是引用。
 
參數傳遞角度理解閉包
1
2
3
4
5
6
7
8
var add_handlers = function (nodes) {
     var i;
     for (i = 0, l = nodes.length; i < l; i ++) {
         nodes[i].onclick = function (e) {
            alert(i);    // 當然這里的結果必然是每次alert的都是節點總數。。。。
         }
     }
};

       此時i是父級函數作用域的變量的引用。給每個節點設置onclick事件的時候將i的引用傳遞給了alert,當我點擊節點觸發onclick事件的時候,i的值已經變成了節點總數。

 

1
2
3
4
5
6
7
8
9
10
11
var add_handlers = function (nodes) {
     var i;
     for (i = 0, l = nodes.length; i < l; i ++) {
  
         nodes[i].onclick = function (i) {
            return function(){
              alert(i);   
           }
         }(i);
     }
};

        這樣修改后之所以正確是因為此時傳進去的是i的值的復制。


檢測類型
          typeof 操作符是確定一個變量是字符串、數值、布爾值,還是 undefined 的最佳工具。如果變 量的值是一個對象或 null,則 typeof 操作符都會返回"object"。
          如果變量是給定引用類型的實例,那么 instanceof 操作符就會返回 true。
1
2
3
4
5
6
7
8
function setName(obj){
     obj.name = "staven" ;
     obj = new Object();
     obj.name = "Bob" ;
}
var person = new Object();
setName(person);
alert(person.name);     //staven

         






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM