這個章節比較偏觀念,如淺複製及深複製的一些概念,我覺得是非常重要的重點。
首先是字串、數值、布林值的賦值
    let a = "A";
    let b = a;
    a = "B";
    console.log(a, b); //  B,A
    let c = 0;
    let d = c;
    c++;
    console.log(c, d); //  1,0
    let e = true;
    let f = e;
    e = !f;
    console.log(e, f); // false,true
發現記憶體沒有A就創建一個A值並賦予記憶體位置,再將g,h,i指向,A的記憶體位置,再來找B,C都沒有,就創建B,C並賦予記憶體位置,再來h指向B記憶體位置,i指向C記憶體位置,最後將g+h=AB並賦予記憶體位置,g指向AB記憶體位置,接著g+i=ABC並賦予記憶體位置,g指向AB記憶體位置。
    let g = "A";
    let h = "A";
    let i = "A";
    h = "B", i = "C", g += h, g += i;
    console.log(g, h, i); //ABC , B ,C

接著是做關於陣列的複製。
    const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
    let player2 = players;
    player2[0] = "jojo";
    console.log(players, player2);
    [0: "jojo",1: "Sarah",2: "Ryan",3: "Poppy"] [0: "jojo",1: "Sarah",2: "Ryan",3: "Poppy"]
發現這並不是我們所要得複製,他們都對應到同一個陣列,所以利用以下幾種方法,可達到互不影響的複製。
法1:slice()方法,利用slice可達到複製,因為slice會額外再產生一個新的陣列。
    let player2 = players.slice();
    player2[0] = "jojo";
    console.log(players, player2);
    (4) ["Wes", "Sarah", "Ryan", "Poppy"] (4) ["jojo", "Sarah", "Ryan", "Poppy"]
法2:concat()方法,被用來合併兩個或多個陣列。此方法不會改變現有的陣列,會回傳呼叫者陣列本身,也就是與players的值合併後的空陣列。
    let player2 = [].concat(players);
    player2[0] = "jojo";
    console.log(players, player2);
法3:解構賦值,將players中的值拆分出來,在合併至player2,回傳一個新的陣列。
    let player2 = [...players];
    player2[0] = "jojo";
    console.log(players, player2);
再來是配合呼叫函數所產生的陣列複製。
    function createObj(name) {
      return {
        //name:name 
        name
      };
    }
    let pr1 = createObj("johnny");
    let pr2 = createObj("lisa");
    let pr3 = createObj("iggy");
    let gr1 = [pr1, pr2, pr3];
    let gr2 = gr1.slice();
    // 由於gr2[0]值為pr1,所以他會去改變gr2[0].name,也就是pr1的值,那我再次獲取gr1,它裡面的pr1也會是改變後的值。
    gr2[0].name = "momo";
    console.log(gr1, gr2); // (3) ["momo", "lisa", "iggy"] 
    // 但如果改為這樣,可發現兩者已互不影響,因為記憶體發現我們的記憶體中並無momo這個值,所以他會創建一個momo的值,並給予他一個記憶體空間,而後我們gr2[0](也就是gr2的pr1)就會指向他,並不影響。
    gr2[0] = "momo";
    console.log(gr1, gr2); // (3) ["johnny", "lisa", "iggy"]  (3) ["momo", "lisa", "iggy"] 

接下來是物件之間的複製與賦值。
    let person = {
      name: 'Wes Bos',
      age: 80
    };
    let p1 = person;
    // 查看記憶體無XXX後,創建一個XXX的值並賦予記憶體空間,接著person在指向他,而與p1互不影響。
    person = "XXX";
    console.log(person, p1); // XXX,{...}
    // 前面步驟與上面一樣,不同的是會改變person.name的值也就是0x1的name,因此p1也會受影響,因為p1指向的也是person所指向的0x1。
    
    person.name = "XXX";
    console.log(person, p1); // {XXX...},{XXX...}

將物件x,y合併後,賦予z,會發現後者的重複的name可以覆蓋前者的。
    let x = {
      name: "bogi",
      age: 87
    };
    let y = {
      name: "dandy"
    };
    let z = Object.assign(x, y);
    console.log(z); // {name: "dandy", age: 87}
如果我們今天在物件新增一個函數,然後以kk複製他並一樣先字串化,然後再轉回obj化,會發現再以kk呼叫就會報錯,因為經stringify,function會被lose掉。
    let k = {
      name: "eva",
      age: 22,
      eat: function () {
        console.log("amazing");
      }
    };
    let kk = JSON.parse(JSON.stringify(k));
    // k.eat()  // amazing
    // kk.eat() // Uncaught TypeError: kk.eat is not a function at <anonymous>:1:4
如果今天我們的物件不含函數,那麼利用JSON.parse(JSON.stringify(wes)),就可以達到deep copy,但如果有就無法。
    const wes = {
      name: 'Wes',
      age: 100,
      social: {
        twitter: '@wesbos',
        facebook: 'wesbos.developer'
      }
    };
    const dev = Object.assign({}, wes);
    // 第一題
    // 互不影響
    dev.social = null;
    console.log(wes); // 不變 {twitter...}; 
    // 第二題
    dev.social.facebook = null;
    console.log(wes.social); // {twitter:..., facebook:null}
    const dev3 = JSON.parse(JSON.stringify(wes));
    
第一題

第二題

第三題:
首先將wes(0x6)的資料,經由stringify將0x6拿出來,並賦予一個新的記憶體空間0x8,再來經過parse,將0x5的資料拿出來(因為0x5為物件(或陣列或函數)資料就會重新賦予記憶體空間)0x9,而後重新創建一個記憶體空間0x10讓wes3指向他。
