想了解JS數據類型轉換嗎?不用找了,這裏都有

案例分析

今天在遇到一個開發中的問題,在進行一個簡單的後臺字段展現的時候,莫名其妙的出現問題。在定位問題的時候,發現一個判斷value>0?A操做:B操做。由於在後臺定義字段時候,明確說明,value的值是一個數字而且>0(確定有值),因此上述的判斷沒有任何的毛病。javascript

可是上線以後,發現有些數據沒有正常展現,在進行接口數據的查詢的時候,發現value有的值居然是B101這類的數據。html

當時的第一反應,好像是沒有問題的,由於在好久以前,我在本身搭建的github博客中對JS數據類型轉換進行了簡單彙總。java

可是沒有出現,就很疑惑,爲了很快的解決線上問題,就沒有深究,直接將判斷條件置換爲value?A操做:B操做git

可是在今天下班的時候,和同事討論到這個問題。發現他也遇到相似JS數據轉換問題。他的問題是[]==![]es6

首先咱們來看第一個狀況:'B101'>0?A操做:B操做的結果爲何?github

其實這裏涉及到一個JS類型轉換的問題。在JS進行不一樣類型的數據類型比較的時候,請記住一條鐵的規則:向數值方向靠攏(這個值不必定必須是數值,也能夠是Boolean,也就是說truefalse,或者也能夠將true當作1,false看出0)。數組

咱們來按上面的'B101'>0來解釋一下:有兩種數據類型String類型的B101Number類型的0。在進行比較的時候,其實JS爲咱們作了一些數值處理,將B101嘗試着轉換爲Number類型 ==>Number('B101')。可是很惋惜,沒有轉換成功。Number('B101')的值爲NANNAN和全部類型的值進行比較都是false。因此第一個例子的返回值爲B操做bash

讓咱們來看我同事提出的問題:[]==![]函數

咱們仍是遵循向數值方向靠攏的規定:有一個元操做!(非)。也就是說將![]先轉換爲基本類型。![]==!Boolean([])他的值爲trueui

這裏有一點須要澄清的是,在[]進行轉變爲基本數據類型的時候,是經歷了一些處理的。先進行valueOf()的取值。若是valueOf返回的是一個基本數據類型,而後進行直接比較,若是仍是一個複雜數據類型,調用toString().

讓咱們來分析一下[]在進行比較的時候,進行了如何的處理

[].valueOf();//[]返回了自己,可是也仍是一個複雜數據類型
[].toString();//"" 返回了一個空串
""==!Boolean([]) //true
複製代碼

而後咱們來分析一個更加直接的列子:

1>{valueOf:function(){return 0},toString:function(){return 2}}
複製代碼

若是在控制檯進行輸出的話,結果是true

而後咱們繼續另一個例子

1>{valueOf:function(){return {}},toString:function(){return 2}}
複製代碼

在控制檯輸出的結果爲false

例如此類的例子不少,可是有一點就是複雜類型數據和基本數據類型進行比較的時候,都是先調用valueOf(),若是返回的值爲基本數據類型,進行比較,若是不是基本數據類型,繼續調用該複雜類型的toString()

由於我原來在github博客中有對應的文章解釋,全部,今天就偷一個懶,直接拿來主義了。

變量

ECMAScript的變量是鬆散類型的,所謂鬆散類型就是能夠保存任何類型的數據。換句話說,每一個變量僅僅是一個用於保存值的佔位符

定義變量的時候用var(ES5) let/const(ES6)等操做符。

var paramA;
let paramB;
const paramC;
複製代碼

上面的代碼定義變量paramX,變量能夠用來保存任何值(如上定義的變量,是未經初始化的變量,會保存一個特殊的值undefined)

數據類型

ECMAScript中有5種簡單數據類型(基本數據類型)

  • 數值(Number):整數和小數(好比1和3.14)
  • 字符串(String):字符組成的文本(好比」Hello World」)
  • 布爾值(Boolean):true(真)和false(假)兩個特定值
  • Undefined:表示「未定義」或不存在,即因爲目前沒有定義,因此此處暫時沒有任何值
  • Null:表示無值,即此處的值就是「無」的狀態。

還有1中複雜數據類型

  • 對象(Object): 本質上是由一組無序的名值對組成。其實對象也能夠細分
  1. 狹義的對象(object)
    2. 數組(array)
    3. 函數(function)

針對於ES5來講只有上訴的6中數據類型,而對於ES6來講又新增了Symbol

typeof操做符

鑑於ECMAScript的數據類型是鬆散的,因此須要一種手段來檢測給定變量的數據類型typeof。

原始數據類型

數值、字符串、布爾值分別返回numberstringboolean

typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"
複製代碼

函數

函數返回function

function f() {}
typeof f
// "function"
複製代碼

undefined

undefined返回undefined

typeof undefined// "undefined"

複製代碼

其餘

除此之外,其餘狀況都返回object

typeof window // "object"
typeof {} // "object"
typeof [] // "object"
typeof null // "object"
複製代碼

須要注意點

Note:對於ES5對於沒有定義的變量typeof undefinedParam //undefined,可是對於用ES6中let/const定義的變量,在變量定義以前進行typeof操做的話,會報錯。

typeof paramVar;//undefined
var paramVar;
typeof paramLet;//ReferenceError:paramLet is not defined
let paramLet
複製代碼

出現上述問題的根源在於兩點

  1. 用var定義的變量會發現變量提高
  2. 用let/const定義的變量存在TDZ(暫時性死區)

Undefined類型

Undefined類型只有一個值,既特殊的undefined。在使用var/let/const等操做符聲明變量可是沒有賦初值時,這個變量的值就是undefined。

undefined的主要目的是用於比較,而在ECMA-262第三版以前是不存在的。在第三版引入這個值是爲了正式區分空對象指針(null)與未經初始化的變量

Null類型

Null類型是第二個只有一個值的數據類型,這個特殊的值是null。從邏輯角度來看,null值表示一個空對象指針,而這也是使用typeof檢測null值的時會返回」object」的緣由。

Boolean

Boolean類型只有兩個字面量:true和false。

雖然Boolean類型的字面量只有兩個,可是ECMAScript中全部類型的值都有與這兩個Boolean值等價的值。要將一個值轉換爲其對應的Boolean值,能夠調用轉型函數Boolean();

數據類型 轉換爲true的值 轉換爲false的值
Boolean true false
String 任何非空字符串 ""(空字符串)
Number 任何非0數字值(+∞) 0和NaN
Object 任何對象 null
Undefined 不適用 undefined

Number類型

ECMAScript中使用IEEE754標準中雙精度浮點數來表示一個數字,不區分整數和浮點數。

IEEE754: 在 IEEE754 中,雙精度浮點數採用 64 位存儲,即 8 個字節表示一個浮點數 。其存儲結構如
下圖所示:


第1位:符號位,0表示正數,1表示負數
第2位到第12位:指數部分
第13位到第64位:小數部分(即有效數字)

指數位能夠經過下面的方法轉換爲使用的指數值:

因爲保存浮點數值須要的內存是整數值的兩倍,所以ECMAScript會不失時機的將浮點數值轉換爲整數值。其實Number類型採用的是雙精度浮點數,可是在保存和應用的時候,爲了內存和速度考慮,會表現出整數和浮點數的區分。

浮點數值

浮點數值:數值中必須包含一個小數點,而且小數點後面必須至少有一位數值。

浮點數值的最高精度是17位小數,但在進行算術計算時其精度遠遠不如整數。這樣就會致使一些違背常理的bug。

let a = 0.1,b = 0.2;
a+b ==0.3;//false
複製代碼

出現這種精度缺失的狀況,在於IEEE754內存結構致使的。 出現上訴問題的深度解析

數值範圍

從存儲結構中能夠看出, 指數部分的長度是11個二進制,即指數部分能表示的最大值是 2047(211-1),取中間值進行偏移,用來表示負指數,也就是說指數的範圍是 [-1023,1024] 。所以,這種存儲結構可以表示的數值範圍爲 21024 到 2-1023 ,超出這個範圍的數沒法表示 。21024 轉換爲科學計數法以下所示: 21024 = 1.7976931348623157 × 10308

所以,JavaScript 中能表示的最大值是 1.7976931348623157e+308,最小值爲 5e-324

這兩個邊界值能夠分別經過訪問 Number 對象的 MAX_VALUE 屬性和 MIN_VALUE 屬性來獲取:

Number.MAX_VALUE; //1.7976931348623157e+308
Number.MIN_VALUE; //5e-324
複製代碼

若是數字超過最大值或最小值,JavaScript 將返回一個不正確的值,這稱爲正向溢出(overflow) 或 負向溢出(underflow) 。

Number.MAX_VALUE+1 == Number.MAX_VALUE; //true
Number.MAX_VALUE+1e292; //Infinity
Number.MIN_VALUE + 1; //1
Number.MIN_VALUE - 3e-324; //0
Number.MIN_VALUE - 2e-324; //5e-324
複製代碼

數值精度

在 64 位的二進制中,符號位決定了一個數的正負,指數部分決定了數值的大小,小數部分決定了數值的精度。

IEEE754 規定,有效數字第一位默認老是1 。所以,在表示精度的尾數前面,還存在一個隱藏位 ,固定爲 1 ,但它不保存在 64 位浮點數之中。也就是說,有效數字老是 1.xx…xx 的形式,其中 xx..xx 的部分保存在 64 位浮點數之中,最長爲52位 。因此,JavaScript 提供的有效數字最長爲 53 個二進制位,其內部實際的表現形式爲:

(-1)^符號位 1.xx…xx 2^指數位 這意味着,JavaScript 能表示並進行精確算術運算的整數範圍爲:

//最大
Math.pow(2, 53)-1 ; // 9007199254740991
//最少
-Math.pow(2, 53)-1 ; // -9007199254740991
複製代碼

能夠經過 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 來分別獲取這個最大值和最小值。

console.log(Number.MAX_SAFE_INTEGER) ; // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER) ; // -9007199254740991
複製代碼

NaN

NaN:即非數值(Not a Number)是一個特殊的數值,這個數值用於表示一個原本要返回數值的操做數未返回數值的狀況。

NaN自己有兩個不一樣尋常的特色

  1. 任何涉及NaN的操做(NaN/10)都會返回NaN
  2. NaN與任何值都不相等,包括NaN自己

針對NaN的這個兩個特色,ECMAScript定義了isNaN()函數。該函數接受一個參數,參數能夠是任何類型。

數值轉換

有三個函數能夠把非數值轉換爲數值:

  • Number() :能夠用於任何數據類型
  • parseInt() : 專門用於把字符串轉成數值
  • parseFloat() : 專門用於把字符串轉成數值

Number()針對不一樣類型的數據類型轉換以下

數據類型 轉換爲true的值
Boolean true=>1 false=>0
Number 簡單的傳入傳出
null 0
undefined NaN
String 1:若是隻包含數字(包括前面帶-/+的狀況),=>十進制數值
2:包含有效的浮點格式(eg:1.1),=>對應的浮點數值
3:含有有效的十六進制格式(eg:0xf),=>相同大小的十進制數值
4:空串 =>0
5:除了前幾個狀況,=>NaN
Object 1:調用對象的valueOf()方法,按照前面的規格進行轉換返回的值
2:若是結果1的值是NaN,則調用對象的toString()方法,再次根據上訴規則轉換返回的值

一元加操做符的操做與Number()函數做用同樣。 使用Number對String進行轉換的時候,會發生違背常規的狀況。
Number('')//0

因此在轉換String類型爲Number類型的時候,通常是用parseInt()。parseInt()函數在轉換String時,更多的是看String是否符合數值模式。它會忽略字符串前面的空格,直到找到第一個非空格字符。若是第一個字符不是數字字符或者負號,parseInt()就會返回NaN。 這樣就規避了利用Number()對''進行轉換的狀況

parseInt('')//NaN
複製代碼

若是想將String轉換爲浮點數類型,可使用parseFloat()。

String類型

String類型是用於表示由零或者多個16位Unicode字符組成的字符序列。

String的特色

ECMAScript中的String是不可變的,也就是說,String一旦建立,他們的值就不能改變。要改變某個變量保存的String,首先要銷燬原來的String,而後再用另外一個包含新值的String填充該變量。

var stringVariable = '北宸';
stringVariable = stringVariable + '南蓁';
複製代碼

實現這個操做的過程以下:

  1. 建立一個能容納8個字符的新String
  2. 在這個String中填充 "北宸"和"南蓁"
  3. 銷燬原來的String "北宸"和"南蓁"

轉換爲String

要把一個值轉換爲String有兩種方式

  1. toString() 返回相應值的字符串表現
    null和undefined值沒有這個方法
  2. String() 可以將任何類型的值轉換爲String.
    String()函數遵循下列轉換規則
    1.若是值有toString()方法,則調用該方法(沒有參數)並返回相應的結果
    2.null =>"null"
    3.undefined => "undefined"

Object類型

一組數據和功能的集合。

對象能夠經過執行new 操做符後跟要建立的對象類型的名稱來建立。而建立Object類型的實例併爲其添加屬性和(或)方法,就能夠建立自定義對象。

在ECMAScript中,Object類型是全部它的實例的基礎換句話說,Object類型所具備的任何屬性和方法也一樣存在於更具體的對象中

Object的每一個實例都具備下列屬性和方法。

屬性或方法 描述
constructor(屬性) 保存着用於建立當前對象的函數
hasOwnProperty(propertyName) 檢查給定的屬性在當前對象實例中是否存在。
propertyName必須是String類型。
isPrototypeof(object) 檢查傳入的對象是不是當前對象的原型
propertyIsEnumerable(prototyName) 給定的屬性是否可以使用for-in來枚舉
propertyName必須是String類型。
toLocaleString() 返回對象的String表示,與執行環境對應
toStirng() 返回對象的Sting表示
valueOf() 返回對象的Sting、Number或者Boolean表示。通常和toString()方法返回值相同
相關文章
相關標籤/搜索