1. 程式人生 > >javascript值傳遞與引用傳遞

javascript值傳遞與引用傳遞

javascript中,變數型別分為基本型別和物件型別,基本型別有以下幾種:string,number,boolean,null,undefined,物件型別就是object,object又分為object,array,function。基本型別是值傳遞,物件型別是引用傳遞。具體來說,就是基本型別a=1,賦給另一個變數b=a,在操作b的時候,a的值不會隨著b的變化而變化。物件型別就不一樣了,如a = [1,2],當我們賦值給b=a,對b進行操作,b[0]=2,這時候a也跟著變化a=[2,2]。這就是值傳遞與引用傳遞的區別。下面我們看具體的示例:

$(function() {
      var a = {name:"aa"};
      var b = ["a","b","c"];
      var c  = a;
      c.id = 101;
      console.log(a); //{name:"aa",id:101}
      var d = b;
      d.push("d");
      console.log(b);//["a","b","c","d"]
      var e = 12;
      var f = e;
      f = f+1;
      console.log(e);//12
});

執行結果如下:

基本型別,值傳遞,這個沒什麼好說,但是物件型別引用傳遞,原因是兩個變數公用一個記憶體,在操作任意變數物件的時候,它們的值都是會發生變化的。那麼問題來了,如果需要做到不改變原始變數的值,怎麼辦,這裡就需要解決一個記憶體問題,就是怎麼把兩個變數變為兩個記憶體中的地址,而不是共用一塊記憶體,這裡就需要用到拷貝。

js中的拷貝分為淺拷貝和深拷貝,所謂淺拷貝就是在變數賦值過程中,只拷貝一級變數,比如a={name:"aa",id:101},b=simpleclone(a),那麼name,id都會拷貝過去,當我們修改name,id的值,不會影響到a。

$(function() {
      function simpleclone(a){
          var res = {};
          for (var i in a){
              res[i] = a[i];
          }
          return res;
      }
      var a = {name:"aa",id:101};
      var b = simpleclone(a);
      b.id = 102;
      console.log(a,b);
});

執行結果如下:

從結果看出,b經過改變,a的值沒有發生變化,賦值之後,b與a的關係切斷了。基本達到了我們的要求。但是淺拷貝有個問題,就是隻是拷貝一級變數,如果一個變數內部有一個巢狀的物件,那麼淺拷貝就失去了作用。

$(function() {
    function simpleclone(a){
        var res = {};
        for (var i in a){
            res[i] = a[i];
        }
        return res;
    }
    var a = {name:"aa",id:101,address:{postcode:100085,detail:"1-3-602"}};
    var b = simpleclone(a);
    b.id = 102;
    console.log(a,b);
    b.address.postcode = 100000;
    console.log(a,b);
});

執行結果:

當改變一級變數id=102時,a,b的id是不相同的,當我們改變b.address.postcode=100000時,結果a.address.postcode也發生了變化,這就有問題了,淺拷貝不能解決變數巢狀 變數的問題。這就需要深拷貝來解決了。

深拷貝的思路就是在淺拷貝的基礎上做了一個判斷,如果是物件變數,即變數巢狀變數,那麼就需要使用遞迴來拷貝。

$(function() {
    function deepclone(a) {
        var res = {};
        for(var i in a){
            if(typeof a[i]=="object"){
                res[i] = deepclone(a[i]);
            }else{
                res[i] = a[i];
            }
        }
        return res;
    }
    var a = {name:"aa",id:101,address:{postcode:100085,detail:"1-3-602"}};
    var b = deepclone(a);
    b.id = 102;
    b.address.postcode = 100000;
    console.log(a,b);
});

執行結果:(這裡的遞迴拷貝不是一個完美的方法,沒有考慮屬性是陣列的情況)

深拷貝的結果是當b=deepclone(a)之後,對b做的任何改變,都不會影響a,這樣就完全解決了物件引用傳遞帶來的問題。深拷貝的實現方式,除了遞迴拷貝之外,還有幾種方式,這裡jQuery提供了一種方法$.extend(true,b,a);該方法的第一個引數如果是false,那麼就是淺拷貝,只有為true時,才是深拷貝。第二個引數是拷貝前的結果,一般是一個空物件,第三個引數是需要拷貝的物件。 還有一種實現方式就是使用JSON物件提供的方法。

function deepclone(a) {
    //return $.extend(true,{},a);
    var tmp = JSON.stringify(a);
    return JSON.parse(tmp);
}