最近頻繁出現的 `parseInt` 和 `Array` 原型方法的題目

首先看下 parseInt 的函數簽名

/** * Converts a string to an integer. * @param s 要被解析的值。若是參數不是一個字符串,則將其轉換爲字符串(使用 ToString 抽象操做)。字符串開頭的空白符將會被忽略。 * @param radix 一個介於2和36之間的整數(數學系統的基礎),表示上述字符串的基數。 * 若是不提供這個參數,以 `0x` 開頭的字符串會被識別成16進制數. * 其它狀況,不一樣環境有不一樣的處理方式,通常會被識別成10進制數 * 若是傳入 0 null undefined 等,當不提供這個參數處理 * 若是傳入不是數字的會把數字,會把參數轉成數字,若是無法轉化,當不提供這個參數處理 * 不提供這個參數不一樣平臺可能會有不一樣,因此,請顯式提供這個參數 */
declare function parseInt(s: string, radix?: number): number;
複製代碼

能夠看到 parseInt 其實有兩個參數,一個是必填的 s,類型是 string;
還有一個可選的 radix,用來表示進制,例如填寫 10 的話,會把第一個參數解析成十進制,若是填寫 16,會把傳進來的字符串解析成十六機制,原則上,這個參數最好都填寫。
返回值是一個整數。若是被解析參數的第一個字符沒法被轉化成數值類型,則返回 NaN面試

幾個簡單的例子

如下這堆都返回 15數組

parseInt('0xF', 16);
parseInt('F', 16);
parseInt('17', 8);
parseInt(021, 8);
parseInt('015', 10); // parseInt(015, 10); 返回 15
parseInt(15.99, 10);
parseInt('15,123', 10);
parseInt('FXX123', 16);
parseInt('1111', 2);
parseInt('15 * 3', 10);
parseInt('15e2', 10);
parseInt('15px', 10);
parseInt('12', 13);
複製代碼

如下例子均返回 -15函數

parseInt('-F', 16);
parseInt('-0F', 16);
parseInt('-0XF', 16);
parseInt(-15.1, 10);
parseInt(' -17', 8);
parseInt(' -15', 10);
parseInt('-1111', 2);
parseInt('-15e1', 10);
parseInt('-12', 13);
複製代碼

如下例子都返回 NaNui

parseInt('Hello', 8); // 根本就不是數值
parseInt('546', 2); // 除了「0、1」外,其它數字都不是有效二進制數字
parseInt('zz', 35); // z 是 35,在 35 進制裏面不可能有 35
複製代碼

返回 NaN 的例子改一下this

parseInt('Hello', 18); // 320, H = 17 e = 14 l = 21,能夠解析的 He 17 * 18 ^ 1 + 14 * 18 ^ 0 = 320
// H = 17 e = 14 l = 21,能夠解析的 Hell 17 * 22 ^ 3 + 14 * 22 ^ 2 + 21 * 22 ^ 1 + 21 * 22 ^ 0 = 188275
parseInt('Hello', 22); // 188275
parseInt('546', 10); // 546 這個不說了
parseInt('zz', 36); // 1295 z = 35,35 * 36 ^ 1 + 35 * 36 ^ 0 = 1295
複製代碼

傳入數字,如下例子都返回 4,先 toString(),而後小數點是無法解析的spa

parseInt(4.7, 10);
parseInt(4.7 * 1e22, 10); // 很是大的數值變成 4
parseInt(0.00000000000434, 10); // 很是小的數值變成 4
複製代碼

最近的一些面試題和變種

map

[1,2,3].map(parseInt)
// [1, NaN, NaN]
map<U>(callbackfn: (value: T, index: number, array: ReadonlyArray<T>) => U, thisArg?: any): U[]; 複製代碼

想必不少人都知道答案了,演算過程說一下大概就是,這裏還須要瞭解一些 map 的函數簽名,map 第一個參數是回調函數,有三個形參,雖然平時通常不會用到第三個,parseInt 接受的參數有兩個,因此實際運行起來的是這樣的code

[1, 2, 3].map((value, index) => parseInt(value, index));
複製代碼

三次演算過程分別是索引

  • parseInt(1, 0),按十進制處理,返回 1
  • parseInt(2, 1),基數不多是 1,返回 NaN
  • parseInt(3, 2),二進制裏面不可能出現 3 的,返回 NaN

filter find findIndex

[1, 2, 3].filter(parseInt); //[1]
[1, 2, 3].find(parseInt); // 1
[1, 2, 3].findIndex(parseInt); // 0
複製代碼

filter 的回調函數簽名和 map 是同樣的,filter 的做用是,過濾掉返回值是假值的函數, find 是找到第一個返回值是真值的 itemfindIndex 的做用是,找到第一個返回是真值的 index字符串

演算過程回調函數

  • parseInt(1, 0),按十進制處理,返回 1,真值,find 返回 1findIndex 返回 0
  • parseInt(2, 1),基數不多是 1,返回 NaN,假值,被過濾了
  • parseInt(3, 2),二進制裏面不可能出現 3 的,返回 NaN,假值,被過濾了

這裏提一下, findfindIndex 是能夠用來作短路運算的,碰到 true,就會退出,能夠用來替代 forEach 這種無法經過 return 退出的,可是這樣代碼語義化就很弱了。

reduce

[1,2,3].reduce(parseInt)
// 1
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: ReadonlyArray<T>) => T, initialValue: T): T;
複製代碼

reduce 的回調參數有四個,一個是上一次循環返回的值,一個是當前值,一個是當前值索引,一個是原數組。這道題裏面沒有涉及到初始值,因此迭代是從 2 開始的。

兩次演算過程分別是:

  • parseInt(1, 2), 二進制 1, 轉成十進制也是 1,這時候,返回 1,進入下一輪迭代
  • parseInt(1, 3), 第二次迭代,上一次迭代的值是 1,當前值是 3, 三進制的 1,返回 1

reduceRight

[1, 2, 3].reduceRight(parseInt);
// NaN
複製代碼

reduceRight 的簽名和 reduce 同樣,不過迭代是從右邊開始的。

兩次演算過程分別是:

  • parseInt(3, 2), 二進制 3, 返回 NaN
  • parseInt(NaN, 1), 第二次迭代,上一次迭代的值是 NaN,當前值是 1, 基數爲 1,返回 NaN

some every

[1, 2, 3].some(parseInt); // true
[1, 2, 3].every(parseInt); // false
複製代碼

some every 的回調函數簽名和 map 同樣,some 是有真值就返回 true, every 是所有都是真值才返回 true

演算過程分別是

  • parseInt(1, 0),按十進制處理,返回 1,真值,some 返回 true,運算結束
  • parseInt(2, 1),基數不多是 1,返回 NaN,假值,every 返回 false,運算結束

這裏提一下, someevery 是能夠用來作短路運算的,some 碰到 true,就會退出, every 碰到 false 就會退出,能夠用來替代 forEach 這種無法經過 return 退出的,可是這樣代碼語義化就很弱了。

forEach

[1, 2, 3].forEach(parseInt); // true
// undefined
複製代碼

這道題要是答錯了,是真的要給本身一巴掌。。。。

[1, 2, 3].map(parseInt); 有沒有通過類型轉換?有的。由於 parseInt 會把第一個傳進來的參數,若是不是 string 就要轉成 string,這裏有個類型轉換

寫在最後

一個看似很簡單的 API,其實考法還挺多的,若是不仔細瞭解的話,就不會知道其中的原理。

相關文章
相關標籤/搜索