keywords:reference-copy,scalar primitives

值 VS. 參考

  • 值的型別完全控制是值的拷貝或參考的拷貝 ( by reference-copy )

      let a = 6;
    
      let b = a; // b 一定是 a 中的值的一份拷貝
    
      b++;
    
      a; // 6
    
      b; // 7
    
      ------------------------------------------
    
      let c = [4,5,6];
    
      let d = c; // d 是指向共有值 [4,5,6] 的一個參考
    
      d.push(7);
    
      c; // [4,5,6,7]
    
      d; // [4,5,6,7]
    

    上方 c、d 都是對同一個共有值 [4,5,6] ( 這是一個複合值 ) 的個別參考,c 與 d 不會有誰比較擁有那個 [4,5,6] 值,兩者都是該值同等的參考

  • 簡單的值 ( 純量的基型值 scalar primitives ) 永遠都是藉由值的拷貝來指定或傳遞:null、undefined、string、number、boolean、symbol ( ES6 )、bigint

      let a = 1n; 
    
      let b = a;
    
      b++;
    
      a; // 1n
    
      b; // 2n
    
  • 複合值的 object、array、function,永遠在指定或傳遞時,建立參考的一份拷貝

      let a = [4,5,6];
    
      let b = a;
    
      a; // [4,5,6]
    
      b; // [4,5,6]
    
      b = [7,8,9];
    
      a; // [4,5,6]
    
      b; // [7,8,9]
    

    參考指向的是值本身,而非變數,無法使用一個參考 ( b ) 來變更另一個參考 ( a ) 所指向的東西,進行 b = [7,8,9] 指定時,完全不會影響到 a 所指的東西 [4,5,6]

  • 這種混淆最常發生在函式參數上,面試也很愛考這種題目

      function f1(p) {
        p.push(4);
    
        p; // [1,2,3,4]
    
        p = [4,5,6];  // 在記憶體建立一個 [4,5,6] 並將它的參考放到 p  
    
        p.push(7);
    
        p; // [4,5,6,7]
      }
    
      let c = [1,2,3];
    
      f1(c);
    
      c; // [1,2,3,4]
    

    沒辦法使用 p 參考變更 c 所指向的東西,只能修改 c 及 p 兩者都指向的那個共有值的內容。
    如果要修改 c 變成 [4,5,6,7] 不能建立一個新的 array 再指定給它,必須修改現有的那個 array 值

      function f1(p) {
        p.push(4);
    
        p; // [1,2,3,4]
    
        p.length = 0;
    
        p.push(4,5,6,7);
    
        p; // [4,5,6,7]
      }
    
      let c = [1,2,3];
    
      f1(c);
    
      c; // [4,5,6,7]
    
  • 要藉由值的拷貝傳入一個複合值,得手動製作它的一個拷貝,讓傳入的參考不能指向原複合值
    不帶參數的 Array.prototype.slice() 預設會製作出 array 的一個全新淺層拷貝

      function f1(p){
        p.push(4);
    
        p; // [1,2,3,4]
    
        p.length = 0;
    
        p.push(4,5,6,7);
    
        p; // [4,5,6,7]
      }
    
      let c = [1,2,3];
    
      f1(c.slice());
    
      c; // [1,2,3]
    
  • 相反的,如果想要傳入一個純量的基型值,並讓其值可被更新,類似參考那樣,可以將該值包裹在一個能夠以參考的拷貝傳遞的複合值

      function f1(wrapper) {
        wrapper.c = 50;
      }
    
      var obj = {
        c:9
      };
    
      f1(obj);
    
      obj.c; //50
    
      obj 就是純量基型值 c 的包裹器
    
#reference-copy #scalar primitives







你可能感興趣的文章

PHP & CGI 相關知識

PHP & CGI 相關知識

演習課 WEEK11

演習課 WEEK11

Express Web App 靜態、動態路由

Express Web App 靜態、動態路由






留言討論