看完標題,入坑過的同學腦海里很快會浮現出這道經典面試題,沒碰到過的同學不妨跟着樓主先來復習一遍 parseInt 的用法(主要參考 MDN)。
parseInt 是 JavaScript 中的一個全局函數(頂級函數),它會將給定的字符串以指定基數(radix/base)解析成為整數。
它的語法非常簡單:
parseInt(string, radix)
第一個參數 string 是要被解析的值,如果參數不是一個字符串,則將其轉換為字符串,字符串開頭的空白符將會被忽略。而第二個參數 radix 是一個 2 到 36 之間的整數值,用於指定轉換中采用的基數,如果不傳入,默認是 10,即按照十進制轉換,這里要注意一點,如果第二個參數傳入 0,和傳入 10 以及不傳入第二個參數等效。函數返回一個整數值,如果解析過程中發生錯誤,將返回 NaN。
返回 NaN 的主要有以下幾種情況:
- 被解析參數的第一個字符無法被轉化成數值類型
- 被解析參數數值太大,不是 radix 進制下的合法數字
- radix 不在 [2, 36] 范圍內(注意其實 0 也是可以的)
console.log(parseInt('hello', 2)); // NaN
console.log(parseInt('3', 2)); // NaN, 3 不是合法的二進制數字
console.log(parseInt('3', 100)); // NaN
其實實際開發中我很少用 parseInt,而是用 +
和 ~~
代替,因為它實在是太長了,但是很顯然 parseInt 的使用范圍更廣。
簡單回顧了 parseInt 的用法,我們來看這道題:
let ans = ["1", "2", "3"].map(parseInt);
console.log(ans);
和大多數人一樣,我的第一反應也是返回 [1, 2, 3]
,這個時候我們有必要回顧下 Array.prototype.map
,該方法的參數是一個函數,而該函數又可以接受三個參數,分別表示數組元素的值,數組元素的在數組中的索引,以及對於數組的引用。一般來說我們直接在 map 方法中傳入匿名函數,但是如果這個函數是在外面定義的,傳入的是方法名呢?
let fn = (...a) => {
console.log(a);
};
let ans = ["1", "2", "3"].map(fn);
// [ '1', 0, [ '1', '2', '3' ] ]
// [ '2', 1, [ '1', '2', '3' ] ]
// [ '3', 2, [ '1', '2', '3' ] ]
我們可以看到,如果沒為該函數指定參數,那么這三個參數都會被傳入!
我們再回到這道題,parseInt 方法是可以傳入 1-2 個參數的,所以 map 傳入的三個參數,其實是都會被傳給 parseInt 方法的,只是 parseInt 會使用前兩個參數而已。
console.log(parseInt('12', 10, 'ignore')); // 12
所以整個過程差不多是這樣的:
let fn = (item, index, array) => {
return parseInt(item, index, array);
};
let ans = ["1", "2", "3"].map(fn);
console.log(ans); // [ 1, NaN, NaN ]
其實就是計算如下:
console.log(parseInt("1", 0)); // 1
console.log(parseInt("2", 1)); // NaN
console.log(parseInt("3", 2)); // NaN
看懂了吧不妨再試試下面這道:
let ans = "1 2 3".replace(/\d/g, parseInt);
console.log(ans);
原理是一樣的,當 replace 的第二個參數是函數的時候,該函數的第一個參數是匹配模式的字符串,接下來的參數是與模式中的子表達式匹配的字符串,可以有 0 個或者多個這樣的參數。接下來的參數是一個整數,聲明了匹配在 StringObject 中出現的位置,最后一個參數是 StringObject 本身。
還是一樣,打印出來看看唄:
let fn = (...a) => {
console.log(a);
};
let ans = "1 2 3".replace(/\d/g, fn);
// [ '1', 0, '1 2 3' ]
// [ '2', 2, '1 2 3' ]
// [ '3', 4, '1 2 3' ]
接下去就簡單了,就是計算下面的表達式了:
console.log(parseInt("1", 0, '1 2 3')); // 1
console.log(parseInt("2", 2, '1 2 3')); // NaN
console.log(parseInt("3", 4, '1 2 3')); // 3
最后再加一道題:
console.log(parseInt(Infinity, 19))
前面說了,第一個參數 string 是要被解析的值,如果參數不是一個字符串,則將其轉換為字符串,所以 Infinity 被轉換成 "Infinity",而 19 進制數中,最大的字符就是 i,代表 18,所以解析的時候遇到 n 就停了,所以輸出 18