iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 9
3
Day 9

轉大人和轉職ㄧ樣不簡單

這樣一句話「JavaScript 是弱型別語言」 好像出現好幾次了,但它常出現也不是沒有原因,因為我們常常會忘記 JavaScript 會幫我們默默地 偷偷的 把資料轉型別這件事,且轉成它認為是合理的型別,但對我們而言卻是雷... 默默哭泣...

在聊如何轉型別或轉成陣列時,先讓我們來聊聊 JavaScript 的型別轉換這件事吧。

就像犀牛大全裡面說的,JavaScript 對值的型別要求很有彈性 是沒原則吧...。例如布林值的truefalse偶爾會變成 1 與 0,對其他的型別也是如此,如果 JavaScript 想要字串,它會把我們給它的任何值都轉成字串; 如果它不是我們想要數字,會把我們給它的任何型別的值轉成數字 好隨心所欲與任性,偶而轉大人轉不過去,它就直接吐 NaN Not a number 給我們。

我們來看幾個例子:

let test1 = "hello " + 42;
test1; // "hello 42" -> 自動把 42 轉成字串,不然叫它怎麼辦

let test2 = "42" + "24"
test2; // "4224"

我們稱這種換換型別的方式為隱性轉型,也就是 JavaScript 自動幫我們轉型這件事。詳細的轉型資料實在太多,在「犀牛大全」裡就有 6,1/2 頁,有興趣可以參考這本犀牛,再加上「你說不知道的 JS」,一邊看一邊實作會更有感覺。其中有許多奇怪的部分,以下,只是舉出其中一個例子而已。 到底有多少規則啊!

數字和運算子的隱性轉型 implicit

在 JavaScript 有個頗怪異的現象,就是如果是「相加」,只要兩個相加數其中一個為「字串數字」如 "42",它就會把另一個數字也轉成字串處理。

"42" + 24; // "4224"
42 + "24"; // "4224"
42 + 24; // "4224"

而這種現象只會出現在「加法」,而在減、乘、除、求餘時,卻會自動把「字串數字」轉成「數字」,而順利進行運算。

"42" - 24; // 18
42 - "24"; // 18
42 - 24; // 18

一些隱性轉型成數字的規則:

  • 如果是可以解析(parse)的字串數字,就會轉成數字
  • 任何不是數字字面值的字串會被轉成NaN
  • true 會被轉成 1,而 false 和空字串""都會被轉成0

顯性轉型 Explicit

顯性轉換型別最簡單的方式是使用Boolean(), Number(), String()或者是Object()這些內建函式。以下是一些範例:

Boolean([]); // true
String(true); // "true"
true.toString() // "true" 與 String(true); 同效果
Number("42"); // 42
Object(42); // Number {42}
  • 除了nullundefined之外,任何值可使用toString()方法,結果和使用String()相同。
  • nullundefined轉為物件,會產生 TypeError

針對陣列的相互轉型別

把陣列轉成字串

我們常常需要把我們的陣列轉成字串,去做其他的處理,最簡單的方式就是使用內建的toString()函式。我們也可以使用String(),但記得要用一個變數去接它,就可達到一樣的效果。

let arr = [1,2,3,4,5]
arr.toString();
arr; // "1,2,3,4,5"

let arr2 = String(arr);
arr2;  // "1,2,3,4,5"

把陣列裡面的值個別轉成數字

我們可以使用map() 去遍歷陣列裡的元素,並調用parseInt()這個可以將其他型別轉成數字的函數,將每個元素轉成數字,要注意parseInt()裡的第二個參數是進位,我們使用十進位去處理,如果沒給第二個參數,它就 會亂給你看 會有不預期的結果。

let arr = ['1','2','3']
let result = arr.map(function (x) { 
  return parseInt(x, 10); 
});

result; // (3) [1, 2, 3]

另一種寫法好神奇

let arr2 = ['10','20','30','40','50']

arr2.map(Number); 
// [10, 20, 30, 40, 50]

如果有字面值無法轉成數字,當然就轉成代表不是數字的NaN

let arr3 = ['10','20','wow','40','Hi']
arr3.map(Number); 
// (5) [10, 20, NaN, 40, NaN]

類陣列(Array-like)轉為陣列

在前幾天的「陣列有哪幾種?」的篇章中,我們有介紹到陣列中的類陣列,而如何把類陣列物件中的值取出,並轉換成單純的陣列?
使用Object.values()可得到一組只有值得陣列,也剛好可以把類陣列的值(value)取出,這個方法也同時適用在一般的物件。

let obj = {
    0: 'a',
    1: 'b',
    2: 'c',
    length: 3
}
Object.values(obj)
// Object.values(obj).map(ele => ele); 另一種寫法
// (4) ["a", "b", "c", 3]

二維陣列轉換成一維陣列

一般我們很少會自己創建多維陣列,所謂一維或二維陣列,就是在一個陣列裡,只有一組中括號,如果這組中括號裡有兩個或兩個以上的陣列(中括號),就稱為多維陣列,當我們拿到這樣的陣列,又必須用方法去處理他,這時就可以用以下的方法,達到「壓平」陣列的效果。
現確認這個陣列的長度是否是零,如果是就不用處理它了,直接回傳零,這只是一個過濾機制。接下來,先將陣列以toString()轉成字串,在用split()以逗號分格每個元素,最後再以Number確保元素為數字。

function flatten(arr) {
  if (arr.length === 0) {
    return 0
  }
  return arr.toString().split(',').map(Number)
}

console.log(flatten([1, [2, [3, [4]], 5], 6], 7,[8, 9] ))
// (6) [1, 2, 3, 4, 5, 6, 7, 8, 9]

感謝 Huli 提醒,在這個範例裡所使用的flatten(),只會對陣列元素是數字的多維陣列起作用,其他數字以外的型別就沒辦法使用flatten()了。

另外有幾種可以把多維陣列壓平的方法,原來MDN 上面都有範例,甚至是用遞迴的方式解決,有興趣的可以參考一下,這個「[遞迴(recurse)只應天上有, 凡人該當用迴圈(iterate)]的寫法。 本人絕對是凡人

大家有沒有發現,我們已經開始使用幾個 JavaScript 的方法在處理這些不是陣列的資料?接下來我們也會一一介紹這些內建的陣列方法喔~

如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~


上一篇
JS 判別是否為陣列 Array
下一篇
JS 如何把陣列 Array 或元素清空和刪除
系列文
JavaScript之一定要了解的 Array 與方法34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
huli
iT邦新手 3 級 ‧ 2019-09-24 15:34:41

最後 flatten 那個只限定於陣列全部都是數字的狀況,如果有除了數字以外的東西就沒辦法用了

在未來會有原生的 Array.prototype.flat 可以用(現在好像還沒正式納入標準,詳情可以自己查一下,我懶得查XD):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

tsuifei iT邦新手 4 級 ‧ 2019-09-24 15:46:35 檢舉

感謝胡大提醒,下次真的要試試不同型別,這就去看一下 MDN 怎麼寫。
再次感謝啊~

我要留言

立即登入留言