iT邦幫忙

2023 iThome 鐵人賽

DAY 2
2

我們先把什麼Vue不Vue的,React不React的放一旁,從一個很基礎,但很多初學者(包含我)卻沒有好好去理解的關鍵概念開始認識,那就是mutable和immutable。如果在網路上查詢這兩個關鍵字的話,通常都可以先接受到一個結論,也就是「普通型別的特性是immutable,物件型別是的特性則是mutable」。但是究竟是什麼意思呢?就接著給他看下去!

什麼是mutable?什麼是immutable?

從字面上看的話,就是「可變(mutable)」和「不可變(immutable)」的意思。那變不變的部分指的是什麼呢?這裡變不變指的是「存在特定記憶體位址的值可變和不可變」。這樣說可能還是很模糊,先讓我們回歸到最單純的JavaScript。

在宣告一個變數時,通常都會幫變數保留一個記憶體空間,不論是原始型別或是物件型別都一樣會有一個記憶體空間,但是原始型別和物件型別卻有一個不一樣的特性,那就是大家應該都知道或聽過的原始型別是傳值(by value),物件型別是傳址(by reference),而這樣的特性也就跟可變和不可變有關聯。

回歸到最初的JavaScript來看傳值(by value)和immutable

如果是一般型別的話,在「宣告變數」、「重新賦值」、「以這個既有變數來宣告新變數」、「在用既有變數來宣告新的變數後,改動新變數的值」的這四種常見的操作,主要會是以下這幾個狀況。

- 宣告變數
JavaScript會幫這個變數建立一個記憶體空間,並且把變數名稱指向這個記憶體空間。(補充: 用var宣告變數,一開始會先給變數一個undefined,最後才會指向實際要賦予的值)

  var number = 1;

https://ithelp.ithome.com.tw/upload/images/20230908/20130914oVd7m0Flkf.png

- 重新賦值
JavaScript會重新幫新的值建立另一個空間,並把這個變數名稱指向新值的記憶體空間,如果沒有其他變數指向原本這個值的記憶體空間,這個記憶體空間就會透過JavaScript的Garbage collection機制把這個記憶體給釋放出來。

  var number = 1;
  number = 2;

https://ithelp.ithome.com.tw/upload/images/20230908/20130914TXV6roAlX3.png

- 以這個既有變數來宣告新的變數
如果把用原本就有的變數賦值給新的變數時,則會變成JavaScript會把這個變數原本的值給複製一份出來,並且保留一個新的記憶體空間給被複製出來的值,再讓新的變數指向這個新的記憶體空間,也就是說雖然既有的變數和新的變數以肉眼來看值都是一樣的,但其實卻是不同的記憶體空間

  var number = 1;
  var newNumber = number;

https://ithelp.ithome.com.tw/upload/images/20230908/20130914rB7EKxVanz.png
https://ithelp.ithome.com.tw/upload/images/20230908/20130914hrcALoOjZK.png

- 在用既有變數來宣告新的變數後,改動新變數的值
在這個情境下,如前面所提到的既有變數和新的變數雖然肉眼看都是相同的值,但是值所存在的記憶體空間卻不相同,所以當改動新變數時,既有的變數並不會變改動到

  var number = 1;
  var newNumber = number;
  newNumber = 4;

https://ithelp.ithome.com.tw/upload/images/20230908/20130914o31nrEsOur.png

以上這些情境也就說明到了傳值(by value),以及不可變動(immutable)的特性。「如果把用原本就有的變數賦值給新的變數時,則會變成JavaScript會把這個變數原本的值給複製一份出來,並且保留一個新的記憶體空間給被複製出來的值,再讓新的變數指向這個新的記憶體空間」這句話也就是在說明傳值;「既有變數和新的變數雖然肉眼看都是相同的值,但是值所存在的記憶體空間卻不相同,所以當改動新變數時,既有的變數並不會變改動到」這部分也就是不可變動,因為原本的值永遠都不會有變動。

回歸到最初的JavaScript來看傳址(by reference)和mutable

接下來看一下傳址(by reference)和可變動(mutable)的部分,這兩個特性會出現在物件型別。我們一樣用「宣告變數」、「重新賦值」、「以這個既有變數來宣告新變數」、「在用既有變數來宣告新的變數後,改動新變數中其中一屬性的值」的這四種常見的變數操作來看會是什麼樣的狀況。

- 宣告變數
JavaScript會幫這個變數建立一個記憶體空間,並且把變數名稱指向這個記憶體空間。這部分跟原始型別沒有差異。

  var profile = {
    name: 'Phoebe',
    age: 18,
  };

https://ithelp.ithome.com.tw/upload/images/20230908/20130914Uq8lyrb68j.png

- 重新賦值
JavaScript會幫新的值保留一個新的記憶體空間,讓這個變數指向新的記憶體空間。

  var profile = {
    name: 'Phoebe',
    age: 18,
  };

  profile = {
    name: 'Jolin',
    age: 18,
  }

https://ithelp.ithome.com.tw/upload/images/20230908/20130914G09f3JP4zy.png

- 以這個既有變數來宣告新的變數
如果想把用原本就有的變數賦值給新的變數時,新的變數會去指向既有變數值的記憶體空間,也就是不僅肉眼看起來是一樣的值,連記憶體空間都相同

  var profile = {
    name: 'Phoebe',
    age: 18,
  };

  var otherProfile = profile;

https://ithelp.ithome.com.tw/upload/images/20230908/20130914WAdsulYoT5.png

- 在用既有變數來宣告新的變數後,改新變數中其中一屬性的值
在這個情境下,如前面所提到的既有變數和新的變數不僅肉眼看起來一樣,記憶體也一樣,所以當改動新變數時,既有的變數當然也會被變動到,因為這兩個變數雖然變數名不同,但其實值都是同一組

  var profile = {
    name: 'Phoebe',
    age: 18,
  };

  var otherProfile = profile;
  otherProfile.name = 'Jolin';

https://ithelp.ithome.com.tw/upload/images/20230908/20130914fSdcouv8sC.png

說到這裡其實應該可以感受到跟前面原始型別的差異了。沒錯!以上這些內容就包含了傳址(by reference),以及可變動(mutable)的特性。「如果想把用原本就有的變數賦值給新的變數時,新的變數會去指向既有變數值的記憶體空間,也就是不僅肉眼看起來是一樣的值,連記憶體空間都相同」這句話也就是在說明傳址,因為他不單單是給新變數相同的值,連記憶體位址都傳給新的變數;「既有變數和新的變數不僅肉眼看起來一樣,記憶體也一樣,所以當改動新變數時,既有的變數當然也會被變動到」這部分也就是可變動的特性,因為原本的值是會被改動到的,在改動相關的操作時,並不會給一個新記憶體空間的值,而是改動到既有記憶體空間的值。

跟學Vue、學React有什麼關係!?

那就是「vue主要是使用mutable的特性,React則相反是主要使用immutale的特性」。雖然不仔細思考,感覺vue和react的用法似乎大同小異,尤其vue3開始,寫法又跟react更相似了,都是用所謂的hooks在做一些操作。但仔細研究的話,其實就可以發現從大至渲染的機制,小至state的改動操作,Vue跟React在根本上都各自帶著mutable和immutable的特性,也因為如此,了解這兩個特性也就變得很重要!

明天就讓我們從最基底的渲染機制,來延伸感受一下mutable和immutable特性為Vue和React所帶來的差異是什麼。


上一篇
【Day 1】為什麼我要從Vue學React?為什麼不只要會用,還要真的懂?
下一篇
【Day 3】可變特性與不可變特性&渲染的觸發與Virtual DOM的產生
系列文
從Vue學React!不只要會用,還要真的懂~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言