iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 14
0
Modern Web

新手也能懂的JS30系列 第 14

JS30-Day14-JS Reference VS Copy

Day14-課題內容

在前幾天的課題當中,我們開始接觸到資料的使用,在今天的課題當中,我們要來認識 javascript 中各種資料型別,以及其在使用上要注意的事項。[1]

Javascript 資料型別

JavaScript 是一种弱類型或者動態語言。代表我們今天我們在創造一個變數的時候,不需要先宣告變數的資料類型,他會在程式運作的過程中自動被定義類型。[2]
而在 javascript 程式語言中,總共含有七種資料型別,其中又可以分成簡單型別與複雜型別。[3]

  1. 簡單資料型別:
  • String
  • Number
  • Boolean
  • Null
  • Undefined
  • Symbol (ECMAScript 6 新定義)
  1. 複雜資料型別:
    Object 是唯一的複雜資料型別。而 ObjectArray Function 都屬於Object的複雜資料型別。

建立資料變數

當我們宣告一個變數時,不同的資料型別將會以不同的方法在記憶體中建立這筆資料。[4]

  1. By Value:
    當我們在建立簡單資料型別的變數時,會在記憶體中存在一個屬於其變數自己的位置。
    因此當我們先建立一簡單資料型別的變數 a,這時候,再我指定另一個變數 b,並它的值等同於 a 的時候, b 實際上會建立另一個獨立的記憶體位置,接著再把 a 的複製到這個獨立的記憶體位置。因 a 和 b 其實是存在於兩個不同的記憶體位置,所以彼此並不會互相影響。這種情況,我們就稱為 By Value。
    範例:
let a = true;
let b = a;
b = false;
console.log(a); //true
console.log(b); //false
  1. By Reference:
    當我們在建立複雜資料型別的變數時,會在記憶體中建立一個位置,然後將該變數資料位置指向該記憶體。
    因此當我們先建立一複雜資料型別的變數 a,這時候,一樣會在記憶體中給它一個位置,但是當我建立一個變數 b,並且把變數 b 的值等同於 a 時,這時候並不會再給它一個新的位置,而是一樣指定到物件 a 的記憶體位置。所以實際上是不會有新的東西被建立,而是將變數 a 和 b 都指到相同的記憶體位置,因此,當 a 的值改變的時候 b 的值也會改變。這種情形我們就稱為 By Reference。
    範例:
let a = [true];
let b = a;
b[0] = false;
console.log(a); //[false]
console.log(b); //[false]

進入課題:

了解不同資料型別之間 By ValueBy Reference 的差異之後,我們可以開始今天的題目:

第一題

Start with strings, numbers and booleans.

let name = 'Kevin';
let age = 27;
let handsome = true;

let copyName = name;
let copyAge = age;
let copyFace = handsome;

console.log('Name:', name, copyName);
console.log('Age:', age, copyAge);
console.log('Handsome:', handsome, copyFace);

後續加上以下的 code 之後再 console.log 一次,會發現 Kevin 系列就會如同前面所提的 by Value 模式,維持一樣的資料內容:

copyName = 'OTree';
copyAge = 100;
copyFace = false;

第二題

Let's say we have an array.

let players = ['Andy', 'Bosh', 'Chris', 'David'];
let copyPlayers = players;

console.log('team1:', players);
console.log('team2:', copyPlayers);

後續加上以下的 code 之後再 console.log 一次,會發現 team1 陣列內容就會如同前面所提的 by reference 模式隨著 team2 改變而被改變:

copyPlayers[1] = 'Ben';
copyPlayers[3] = 'Dick';

從以上的結果來看,如果我們今天需要複製一個陣列,並修改複製出來的陣列內容,應該要怎麼做呢?
我們可以透過會建立一個新的陣列的方法,來複製原始陣列,如此一來我們就可以對複製出來的陣列為所欲為,且不會對原始陣列造成傷害:

  1. slice() : 擷取陣列中的某一段成為新的陣列。
let players = ['Andy', 'Bosh', 'Chris', 'David'];
let copyPlayers = players.slice();

copyPlayers[1] = 'Ben';
copyPlayers[3] = 'Dick';

console.log('team1:', players);
console.log('team2:', copyPlayers);
  1. concat() :回傳一個包含呼叫者陣列本身的值,以及被當作參數提供的陣列或是值的而成的新陣列。
let players = ['Andy', 'Bosh', 'Chris', 'David'];
let copyPlayers = [].concat(players);

copyPlayers[1] = 'Ben';
copyPlayers[3] = 'Dick';

console.log('team1:', players);
console.log('team2:', copyPlayers);
  1. Array.from() :會從類陣列(array-like)或是可迭代的物件建立一個新的陣列。
let players = ['Andy', 'Bosh', 'Chris', 'David'];
let copyPlayers = Array.from(players);

copyPlayers[1] = 'Ben';
copyPlayers[3] = 'Dick';

console.log('team1:', players);
console.log('team2:', copyPlayers);

以上的方法都可以建立一個新的陣列,印出來的內容如下,而其他還有許許多多方法可以利用,大家可以嘗試適合自己的方法。

第三題

with Objects.

let Kevin = {
    name: 'Kevin',
    age: 27
};

let copyKevin = Kevin;
console.log(Kevin);
console.log(copyKevin);

後續加上以下的 code 之後再 console.log 一次,會發現 Kevin 以及 copyKevin 物件內容被一同改變:

copyKevin['name']='OTree';
copyKevin['age']=100;

在這邊我們一樣可以利用會建立新物件的 object.assign() 方法,來複製原始物件,如此一來就不會更動到原始物件內的屬性:

let Kevin = {
    name: 'Kevin',
    age: 27
};

let copyKevin = Object.assign({}, Kevin);
copyKevin['name']='OTree';
copyKevin['age']=100;

console.log(Kevin);
console.log(copyKevin);

但如果今天我們的物件中又包了一個物件,我們就必須使用深層複製,否則內層物件中的屬性,還是會一樣指到相同的位置:

JSON.parse(JSON.stringify(object));

淺層

let Kevin = {
    address:{
    city:'Tainan'
    }
};
let copyKevin = Object.assign({}, Kevin);
copyKevin['address']['city']='Yunlin';

console.log(Kevin);
console.log(copyKevin);

深層

let Kevin = {
    address:{
    city:'Tainan'
    }
};
let copyKevin = JSON.parse(JSON.stringify(Kevin));
copyKevin['address']['city']='Yunlin';

console.log(Kevin);
console.log(copyKevin);

總結

今天學習到以下的東西:

  1. Javascript的資料型別
  2. By Value 以及 By Reference 變數資料的差異。

在今天的課題中,我們了解到不同的變數資料型別在使用時可能會遇到的地雷,以及該如何解決的方法,讓我們在使用或修改變數資料的時候可以更加安穩。
以上是今天的方法與心得,感謝您的閱讀。

參考資料

  1. javascript30
  2. JavaScript data types and data structures
  3. Javascript判斷變數型別的陷阱與正確的處理方式
  4. 談談JavaScript中by reference和by value的重要觀念-PJChen

上一篇
JS30-Day13-Slide in on Scroll
下一篇
JS30-Day15-LocalStorage
系列文
新手也能懂的JS3030
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言