0%

如何轉型別為陣列

Day 09

轉大人和轉職ㄧ樣不簡單

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

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

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

我們來看幾個例子:

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

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

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

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

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

1
2
3
'42' + 24; // "4224"
42 + '24'; // "4224"
42 + 24; // "4224"

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

1
2
3
'42' - 24; // 18
42 - '24'; // 18
42 - 24; // 18

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

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

顯性轉型 Explicit

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

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

針對陣列的相互轉型別

把陣列轉成字串

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

1
2
3
4
5
6
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()裡的第二個參數是進位,我們使用十進位去處理,如果沒給第二個參數,它就 會亂給你看 會有不預期的結果。

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

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

另一種寫法好神奇

1
2
3
4
let arr2 = ['10', '20', '30', '40', '50'];

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

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

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

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

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

1
2
3
4
5
6
7
8
9
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確保元素為數字。

1
2
3
4
5
6
7
8
9
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 的方法在處理這些不是陣列的資料?接下來我們也會一一介紹這些內建的陣列方法喔~

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