官术网_书友最值得收藏!

1.2.2 Number類型轉換

在實際的開發中,我們經常會遇到將其他類型的值轉換為Number類型的情況。在JavaScript中,一共有3個函數可以完成這種轉換,分別是Number()函數、parseInt()函數、parseFloat()函數,接下來就詳細地講解3個函數的使用方法與注意事項。

1. Number()函數

Number()函數可以用于將任何類型轉換為Number類型,它在轉換時遵循下列規則。

① 如果是數字,會按照對應的進制數據格式,統一轉換為十進制并返回。


Number(10);    // 10
Number(010);   // 8,010是八進制的數據,轉換成十進制是8
Number(0x10);  // 16,0x10是十六進制數據,轉換成十進制是16

② 如果是Boolean類型的值,true將返回為“1”,false將返回為“0”。


Number(true);  // 1
Number(false); // 0

③ 如果值為null,則返回“0”。


Number(null);  // 0

④ 如果值為undefined,則返回“NaN”。


Number(unde?ned); // NaN

⑤ 如果值為字符串類型,則遵循下列規則。

· 如果該字符串只包含數字,則會直接轉換成十進制數;如果數字前面有0,則會直接忽略這個0。


Number('21');  // 21
Number('012'); // 12

· 如果字符串是有效的浮點數形式,則會直接轉換成對應的浮點數,前置的多個重復的0會被清空,只保留一個。


Number('0.12');  // 0.12
Number('00.12'); // 0.12

· 如果字符串是有效的十六進制形式,則會轉換為對應的十進制數值。


Number('0x12'); // 18
Number('0x21'); // 33

· 如果字符串是有效的八進制形式,則不會按照八進制轉換,而是直接按照十進制轉換并輸出,因為前置的0會被直接忽略。


Number('010');   // 10
Number('0020');  // 20

· 如果字符串為空,即字符串不包含任何字符,或為連續多個空格,則會轉換為0。


Number('');     // 0
Number('   ');  // 0

· 如果字符串包含了任何不是以上5種情況的其他格式內容,則會返回“NaN”。


Number('123a'); // NaN
Number('a1.1'); // NaN
Number('abc'); // NaN

⑥ 如果值為對象類型,則會先調用對象的valueOf()函數獲取返回值,并將返回值按照上述步驟重新判斷能否轉換為Number類型。如果都不滿足,則會調用對象的toString()函數獲取返回值,并將返回值重新按照步驟判斷能否轉換成Number類型。如果也不滿足,則返回“NaN”。

以下是通過valueOf()函數將對象正確轉換成Number類型的示例。


var obj = {
   age: 21,
   valueOf: function () {
      return this.age;
   },
   toString: function () {
      return 'good';
   }
};

Number(obj);  // 21

以下是通過toString()函數將對象正確轉換成Number類型的示例。


ar obj = {
   age: '21',
   valueOf: function () {
       return [];
   },
   toString: function () {
       return this.age;
   }
};

Number(obj);  // 21

以下示例是通過valueOf()函數和toString()函數都無法將對象轉換成Number類型的示例(最后返回“NaN”)。


var obj = {
   age: '21',
   valueOf: function () {
       return 'a';
   },
   toString: function () {
       return 'b';
   }
}

Number(obj);  // NaN

如果toString()函數和valueOf()函數返回的都是對象類型而無法轉換成基本數據類型,則會拋出類型轉換的異常。


var obj = {
   age: '21',
   valueOf: function () {
       return [];
   },
   toString: function () {
       return [];
   }
};

Number(obj);  // 拋出異常TypeError: Cannot convert object to primitive value

2. parseInt()函數

parseInt()函數用于解析一個字符串,并返回指定的基數對應的整數值。

其語法格式如下。


parseInt(string, radix);

其中string表示要被解析的值,如果該參數不是一個字符串,那么會使用toString()函數將其轉換成字符串,而字符串前面的空白符會被忽略。

radix表示的是進制轉換的基數,數據范圍是2~36,可以是使用頻率比較高的二進制、十進制、八進制和十六進制等,默認值為10。因為對相同的數采用不同進制進行處理時可能會得到不同的結果,所以在任何情況下使用parseInt()函數時,建議都手動補充第二個表示基數的參數。

parseInt()函數會返回字符串解析后的整數值,如果該字符串無法轉換成Number類型,則會返回“NaN”。

在使用parseInt()函數將字符串轉換成整數時,需要注意以下5點。

(1)非字符串類型轉換為字符串類型

如果遇到傳入的參數是非字符串類型的情況,則需要將其優先轉換成字符串類型,即使傳入的是整型數據。


parseInt('0x12', 16);  // 18
parseInt(0x12, 16);    // 24

第一條語句直接將字符串"0x12"轉換為十六進制數,得到的結果為1×16+2=18;

第二條語句由于傳入的是十六進制數,所以會先轉換成十進制數18,然后轉換成字符串"18",再將字符串"18"轉換成十六進制數,得到的結果為1×16+8=24。

(2)數據截取的前置匹配原則

parseInt()函數在做轉換時,對于傳入的字符串會采用前置匹配的原則。即從字符串的第一個字符開始匹配,如果處于基數指定的范圍,則保留并繼續往后匹配滿足條件的字符,直到某個字符不滿足基數指定的數據范圍,則從該字符開始,舍棄后面的全部字符。在獲取到滿足條件的字符后,將這些字符轉換為整數。


parseInt("fg123", 16);  // 15

對于字符串'fg123',首先從第一個字符開始,'f'是滿足十六進制的數據,因為十六進制數據范圍是0~9,a~f(A~F),所以保留'f';然后是第二個字符'g',它不滿足十六進制數據范圍,因此從第二個字符至最后一個字符全部舍棄,最終字符串只保留字符'f';然后將字符'f'轉換成十六進制的數據,為15,因此最后返回的結果為“15”。

如果遇到的字符串是以"0x"開頭的,那么在按照十六進制處理時,會計算后面滿足條件的字符串;如果按照十進制處理,則會直接返回“0”。


parseInt('0x12',16);   // 18 = 16 + 2
parseInt('0x12',10);   // 0

需要注意的一點是,如果傳入的字符串中涉及算術運算,則不執行,算術符號會被當作字符處理;如果傳入的參數是算術運算表達式,則會先運算完成得到結果,再參與parseInt()函數的計算。


parseInt(15 * 3, 10);   // 45,先運算完成得到45,再進行parseInt(45, 10)的運算
parseInt('15 * 3', 10); // 15,直接當作字符串處理,并不會進行乘法運算

(3)對包含字符e的不同數據的處理差異

處理的數據中包含字符e時,不同進制數的處理結果有很大不同。

當傳入的參數本身就是Number類型時,會將e按照科學計數法計算后轉換成字符串,然后按照對應的基數轉換得到最終的結果。

如果傳入的字符串中直接包含e,那么并不會按照科學計數法處理,而是會判斷字符e是否處在可處理的進制范圍內,如果不在則直接忽略,如果在則轉換成對應的進制數。

以下為幾行代碼以及相應的執行結果。


parseInt(6e3, 10);     // 6000
parseInt(6e3, 16);      // 24576
parseInt('6e3', 10);    // 6
parseInt('6e3', 16);     // 1763

對于上述4個不同的結果,詳細解釋如下。

第一條語句parseInt(6e3, 10),首先會執行6e3=6000,然后轉換為字符串"6000",實際執行的語句是parseInt('6000', 10),表示的是將字符串"6000"轉換為十進制的整數,得到的結果為6000。

第二條語句parseInt(6e3, 16),首先會執行6e3=6000,然后轉換為字符串"6000",實際執行的語句是parseInt('6000', 16),表示的是將字符串"6000"轉換為十六進制的數,得到的結果是6×163 = 24576。

第三條語句parseInt('6e3', 10),表示的是將字符串'6e3'轉換為十進制的整數,因為字符'e'不在十進制所能表達的范圍內,所以會直接省略,實際處理的字符串只有"6",得到的結果為6。

第四條語句parseInt('6e3', 16),表示的是將字符串'6e3'轉換為十六進制的整數,因為字符'e'在十六進制所能表達的范圍內,所以會轉換為14進行計算,最后得到的結果為6×162 +14×16 + 3 = 1763。

(4)對浮點型數的處理

如果傳入的值是浮點型數,則會忽略小數點及后面的數,直接取整。


parseInt('6.01', 10); // 6
parseInt('6.99', 10); // 6

經過上面的詳細分析,我們再來看看以下語句的執行結果。以下語句都會返回“15”,這是為什么呢?


parseInt("0xF", 16);    // 十六進制的F為15,返回“15”
parseInt("F", 16);      // 十六進制的F為15,返回“15”
parseInt("17", 8);      // 八進制的"17",返回結果為1×8 + 7 = 15
parseInt(021, 8);      // 021先轉換成十進制得到17,然后轉換成字符串"17",再轉換成
                      // 八進制,返回結果為1×8 + 7 = 15
parseInt("015", 10);   // 前面的0忽略,返回“15”
parseInt(15.99, 10);   // 直接取整,返回“15”
parseInt("15,123", 10); // 字符串"15,123"一一匹配,得到"15",轉換成十進制后返回“15”
parseInt("FXX123", 16); // 字符串"FXX123"一一匹配,得到"F",轉換成十六進制后返回“15”
parseInt("1111", 2);    // 1×23 + 1×22 + 1×2 + 1 = 15
parseInt("15 * 3", 10); // 字符串中并不會進行算術運算,實際按照"15"進行計算,返回“15”
parseInt("15e2", 10);   // 實際按照字符串"15"運算,返回“15”
parseInt("15px", 10);   // 實際按照字符串"15"運算,返回“15”
parseInt("12", 13);     // 按照十三進制計算,返回結果為1×13 + 2 = 15

(5)map()函數與parseInt()函數的隱形坑

設想這樣一個場景,存在一個數組,數組中的每個元素都是Number類型的字符串['1','2', '3', '4'],如果我們想要將數組中的元素全部轉換為整數,我們該怎么做呢?

我們可能會想到在Array的map()函數中調用parseInt()函數,代碼如下。


var arr = ['1', '2', '3', '4'];

var result = arr.map(parseInt);

console.log(result);

但是在運行后,得到的結果是[1, NaN, NaN, NaN],與我們期望的結果[1, 2, 3, 4]差別很大,這是為什么呢?

其實這就是一個藏在map()函數與parseInt()函數中的隱形坑。


arr.map(parseInt);

上面的代碼實際與下面的代碼等效。


arr.map(function (val, index) {
    return parseInt(val, index);
});

parseInt()函數接收的第二個參數實際為數組的索引值,所以實際處理的過程如下所示。


parseInt('1', 0);  // 1
parseInt('2', 1);  // NaN
parseInt('3', 2);  // NaN
parseInt('4', 3);  // NaN

任何整數以0為基數取整時,都會返回本身,所以第一行代碼會返回“1”。

第二行代碼parseInt('2', 1),因為parseInt()函數對應的基數只能為2~36,不滿足基數的整數在處理后會返回“NaN”;

第三行代碼parseInt('3', 2),表示的是將3處理為二進制表示,實際上二進制時只有0和1,3超出了二進制的表示范圍,無法轉換,返回“NaN”;

第四行代碼parseInt('4', 3),與第三行類似,4無法用三進制的數據表示,返回“NaN”。

因此我們在map()函數中使用parseInt()函數時需要注意這一點,不能直接將parseInt()函數作為map()函數的參數,而是需要在map()函數的回調函數中使用,并盡量指定基數,代碼如下所示。


var arr = ['1', '2', '3', '4'];

var result = arr.map(function (val) {  
    return parseInt(val, 10);
});

console.log(result);  // [1, 2, 3, 4]

3. parseFloat()函數

parseFloat()函數用于解析一個字符串,返回對應的浮點數。如果給定值不能轉換為數值,則會返回“NaN”。

與parseInt()函數相比,parseFloat()函數沒有進制的概念,所以在轉換時會相對簡單些,但是仍有以下一些需要注意的地方。

① 如果在解析過程中遇到了正負號(+ / -)、數字0~9、小數點或者科學計數法(e / E)以外的字符,則會忽略從該字符開始至結束的所有字符,然后返回當前已經解析的字符的浮點數形式。

其中,正負號必須出現在字符的第一位,而且不能連續出現。


parseFloat('+1.2');   // 1.2
parseFloat('-1.2');   // -1.2
parseFloat('++1.2');  // NaN,符號不能連續出現
parseFloat('--1.2');  // NaN,符號不能連續出現
parseFloat('1+1.2');  // 1,'+'出現在第二位,不會當作符號位處理

② 字符串前面的空白符會直接忽略,如果第一個字符就無法解析,則會直接返回“NaN”。


parseFloat('  1.2'); // 1.2
parseFloat('f1.2');  // NaN

③ 對于字符串中出現的合法科學運算符e,進行運算處理后會轉換成浮點型數,這點與parseInt()函數的處理有很大的不同。


parseFloat('4e3');   // 4000
parseInt('4e3', 10); // 4

parseFloat()函數在處理'4e3'時,會先進行科學計數法的運算,即4e3 = 4×1000 = 4000,然后轉換成浮點型數,返回“4000”;

parseInt()函數在以十進制處理'4e3'時,不會進行科學計數法的運算,而是直接從第一個字符開始匹配,最終匹配成功的字符為'4',轉換成整型后,返回整數“4”。

④ 對于小數點,只能正確匹配第一個,第二個小數點是無效的,它后面的字符也都將被忽略。


parseFloat('11.20');  // 11.2
parseFloat('11.2.1'); // 11.2

下面是使用parseFloat()函數的綜合實例。


parseFloat("123AF");   // 123,匹配字符串'123'
parseFloat("0xA");     // 0,匹配字符串'0'
parseFloat("22.5");    // 22.5,匹配字符串'22.5'
parseFloat("22.3.56"); // 22.3,匹配字符串'22.3'
parseFloat("0908.5");  // 908.5,匹配字符串'908.5'

4. 結論

雖然Number()、parseInt()和parseFloat()函數都能用于Number類型的轉換,但是它們在處理方式上還是有一些差異的。

· Number()函數轉換的是傳入的整個值,并不是像parseInt()函數和parseFloat()函數一樣會從首位開始匹配符合條件的值。如果整個值不能被完整轉換,則會返回“NaN”。

· parseFloat()函數在解析小數點時,會將第一個小數點當作有效字符,而parseInt()函數在解析時如果遇到小數點會直接停止,因為小數點不是整數的一部分。

· parseFloat()函數在解析時沒有進制的概念,而parseInt()函數在解析時會依賴于傳入的基數做數值轉換。

主站蜘蛛池模板: 达日县| 松阳县| 抚远县| 霍林郭勒市| 泽库县| 育儿| 辽中县| 奉贤区| 龙山县| 桓仁| 涟水县| 天气| 扶余县| 固镇县| 拜城县| 牙克石市| 吉木萨尔县| 迁西县| 九江县| 楚雄市| 德州市| 渝北区| 大石桥市| 宣武区| 锡林郭勒盟| 宾阳县| 枣强县| 宣威市| 阿巴嘎旗| 东山县| 加查县| 正镶白旗| 巨野县| 西贡区| 唐河县| 嘉兴市| 江永县| 剑川县| 垣曲县| 时尚| 和平区|