類型 chrome
首先明確一點,Js中的類型是針對值來講,而不是針對變量,值就是所謂的42, 'abc', false 等能用js 操做的數據。在js 中說某某某是什麼數據類型,實際上是說的這些值是什麼類型。值呢?有7種數據類型: number, string, boolean, null, undefined, object, symbol. 42 就是number 類型了。怎麼判斷出來的,最簡單的辦法就是typeof 操做符了,它返回一個字符串來表示類型數組
console.log(typeof 42); // 'number'
這時,你可能想到,不對啊,之前也用typeof 操做過變量啊?也返回類型了啊。瀏覽器
let a = 42 console.log(typeof a); // 'number'
其實這裏仍然是對值進行的類型判斷,由於你不能說變量a就是number 類型,由於 js 是弱類型語言,徹底能夠把從新賦值爲一個變量。安全
let a = 42 console.log(typeof a); // 'number' a = 'str'; console.log(typeof a); // 'string'
這時,你就說不出變量a 是什麼類型了。在js 中,若是對一個變量進行typeof 操做,必定是對當時變量所指向或所包含的值進行typeof 操做,變量沒有類型,值有。函數
但使用typeof 進行類型判斷的時候,它有一個bug, typeof null 返回的是'object' 而不是'null'. null 值是'null' 類型的惟一值,它居然返回了'object'. 這時,若是你就想用typeof 操做符來判斷一個值是否是null, 你就要再加一個判斷了。只有對象和null 執行typeof 操做時候,才返回'object', 只要找出兩者的不一樣就能夠了,很簡單,全部對象都是真值,null 是假值,!a 是true 就能夠區分了。因此使用typeof 判斷null的時候,以下學習
let a = null; (!a && typeof a === 'object') // true
其時 typeof 還一個小問題,就是typeof 一個函數的時候,返回的是一個'funciton', spa
let a = () => {}; console.log(typeof a); // 'function'
這可能讓人產生誤會,誤覺得'funciton' 也是一種數據類型,其實並非,全部的函數都是對象,不過這也提供了一個判斷函數的簡便方法。prototype
固然,typeof 操做符還有一個好處,就是若是一個變量沒有聲明的話,執行typeof 操做,不會報錯,而是返回undefined, 這就是提供了一個安全的操做,由於,若是你直接引用一個沒有聲明的變量就會報錯。有時,你想判斷一個變量存不存在,如要寫a == undefined, 完了,報錯了,引用了一個沒有聲明的變量a. 若是使用 typeof a == undefined, 沒有問題。3d
Number類型code
Js 中,只有一種數字類型,就是Number, 實際上它是雙精度的浮點型,在其它語言中稱爲double,也就是說Js 中沒有整數類型, 所謂的整數只不過是沒有小數,或小數後面全是0,如42 或42.00。 默認狀況下, 數值的輸出方式,都是10進制,而且會把末尾的0 去掉。
var a = 42.300; var b = 42.0; console.log(a); // '42.3' console.log(b) // 42
可是若是一個數特別大或特別小的話,它會以指數形式進行輸出,在chrome 瀏覽器中,只要整數大於20次方,它就會轉化爲指向,小數的話,只要後面有7位,就會轉化爲指數
var a = 5000000000000000000000; var b = 0.0000005; console.log(a); // 5e+21 console.log(b) // 5e-7
使用浮點數來表示數值時,它有一個問題, 就是0.1 + 0.2 === 0.3 爲false. 計算整數的時候,沒有問題,計算小數就有可能出問題,那怎麼辦法?怎麼才能讓0.1 + 0.2 和0. 3 進行比較的時候,表示相等呢?一種是辦法是設置一個容錯的邊界, 當小於這個值 的時候,就表示這兩個值相等了,這個值在js 中是2的-52 次方Math.pow(2,-52),Es6 專門定義了這個常量Number.EPSILON, 只要二者進行比較小於這個數,就證實這兩個值相等。
// 無限接近相等 function isCloseEnoughToEqual(n1,n2) { return Math.abs( n1 - n2 ) < Number.EPSILON; } let a = 0.1 + 0.2; let b = 0.3 console.log(isCloseEnoughToEqual(a, b)) // true
計算整數沒有問題,這個整數也是有邊界的, 對於double雙精度浮點數,用 1 位表示符號,用 11 位表示指數,52 位表示尾數,因此浮點數表示的最大整數是2的53次方-1(Math.pow(2, 53))最小整數是-2的53次方, 即[-2^53, 2^53 - 1], 超出了這個邊界,計算也是不許確
let a = 9007199254740992; // 2^53 let b = a + 1; console.log(a == b) // true
a + 1 和a 是相等的,因此出現了問題了。爲些,Es6 定義了安全數值 的字面量和判斷安全數值的方法 Number.MAX_SAFE_INTEGER, Number.MIN_SFTE_INTEGER
以及Number.isSafeInteger(); 固然也提供了判斷整數的方法Number.isInteger();
let a = 9007199254740991; // 2^53 -1 let b = a + 1; console.log(Number.isSafeInteger(a)) // true console.log(Number.isSafeInteger(b)) // false console.log(Number.isInteger(a)) // true console.log(Number.isInteger(b)) // true
a 和 b 都是整數,但a 是安全整數,b 不是
Number 類型中的特殊值--- NaN。當咱們執行算術操做的時候,這個操做並無成功,按理說,它應該報錯,可是Js 並不會,而是返回特殊的值NaN。
let a = 2 / 'foo'; console.log(a ) // NaN
咱們怎麼判斷值是NaN, 可能最簡單的就是 它=== NaN, 可是很不幸,NaN 和它自己並不相等,NaN === NaN 返回的是false. 其次還有一個isNaN 的函數來判斷NaN, 可是它也有點問題,傳給isNaN的參數,首先會進行自動類型轉化,看能不能轉化成數字,如能就是返回true, 若是不能返回false.
let a = 2 / 'foo'; console.log(isNaN(a)) // true let b = 'foo'; console.log(isNaN(b)) // true
能夠看到 b 不是NaN, 可是isNaN 仍然返回了true, 也就是說,即便isNaN() 返回了true, 咱們也不能肯定這個值是否是NaN。爲了解決這個問題,ES6增長了Number.isNaN(), 若是值爲NaN, 它返回ture ,不然返回false.
let a = 2 / 'foo'; console.log(Number.isNaN(a)) // true let b = 'foo'; console.log(Number.isNaN(b)) // false
Number.isNaN() 是怎麼判斷的呢?首先它判斷這個值是否是number 類型,NaN 做爲值,它實際上是number 類型
let a = 2 / 'foo'; console.log(typeof a === 'number') // true
其次纔是調用isNaN 方法來判斷。
Number 類型中的特殊值--- +0 和-0. Js 中的0 有兩個,+0 和-0. 除了字面量的方式能夠獲得-0 外,使用* 或 / 操做符,也能夠獲得,但+ - 操做符不能。
let a = -1 * 0; let b = 0 / -1; console.log(a, b) // -0
有兩個0 也沒關係,可是它有幾個奇怪的行爲
1, +0 和 -0 使用== 或=== 比較的時候,是相等。
let a = -0; let b = 0 console.log(a === b) // true
其實它兩個是不相等,因此ES6 增長了Object.is() 方法,來判斷它兩個並不相等。
2, -0 轉化成字符串的時候,輸出的結果是‘0’ ,而是不-0. JSON.stringify(-0) 也是獲得'0'
let a = -0; console.log(a.toString()) // '0'
console.log(JSON.stringify(a)) // '0'
然而當一個'-0' 字符串轉化數字的時候,它返回的是-0, 正常的。
+"-0"; // -0 Number( "-0" ); // -0 JSON.parse( "-0" ); // -0
null 和undefined
null 是一個關鍵字,不能用它做爲變量名,更不能給它賦值,但undefined 不是,它能夠是一個標示符,能夠給它賦值,固然,這僅限在非嚴格模式,若是是嚴格模式的話,會報錯。
var undefined = 2;
"use strict"; var undefined = 2; // 報錯
因爲undefined 能夠被改寫,有一個void 操做符,它後面能夠是任何表達式,返回的值是undefined, 不過通常使用 void 0, 這樣undefined 就不會被改寫了。
console.log(void 0 === undefined) // true
對象(引用類型)
若是一個值執行typeof 操做返回 ‘object’,那麼它就是引用類型,其實,還能夠進行細分,它具體是對象下面的哪個類型,數組,仍是函數,使用的是Object.prototype.toString.call(值)
let a = [1,2]; let b = function(){}; let c = new Date(); console.log(Object.prototype.toString.call(a)) // '[object Array]' Array 類型 console.log(Object.prototype.toString.call(b)) // '[object Function]' Function 類型 console.log(Object.prototype.toString.call(c)) // '[object Date]' Date 類型
那對基本數據類型調用toString() 方法呢?它返回基本類型的包裝類型,甚至對null, undefined 均可以調用, 返回值以下
console.log(Object.prototype.toString.call(1)) // '[object Number]' console.log(Object.prototype.toString.call('abc')) // '[object String]' console.log(Object.prototype.toString.call(false)) // '[object Boolean]' console.log(Object.prototype.toString.call(null)) // '[object Null]' console.log(Object.prototype.toString.call(undefined)) // '[object Undefined]' console.log(Object.prototype.toString.call(Symbol())) // '[object Symbol]'
數組類型
1, 刪除數組元素的時候,不要用delete, 使用delete 能夠把數組中的元素及元素在數組中的位置(slot)刪除掉, 但不用更新數組的length 長度。
let a = [1, 2]; delete a[0]; console.log(a); console.log(a.length)
下圖是chrome 瀏覽器的返回值。
可使用splice() 進行刪除
2, 不要建立稀疏數組。當建立稀疏數組的時候,兩個不相鄰元素之間的slot 是不存在的,a[0] 和a[2] 之間並無slot, 儘管獲取到它的值是undefined
var a = [ ]; a[0] = 1; // 沒有 a[1] slot a[2] = 3; a[1]; // undefined a.length; // 3
當咱們使用構造函數建立數組時, 給它傳遞一個數字,它就會建立length 爲參數的數組,這個數組其實也是一個稀疏數組. 好比,你傳遞了一個3,那麼建立的數組的length 爲3,咱們覺得這個數組有了3個slot, 值爲undefined, 其實它沒有任何的slot. 當你使用forEach 的時候,什麼都沒有輸出
arr.forEach((item, index) => {
console.log(item);
console.log(index);
})
3, 儘管數組是對象,但千萬不要做爲對象進行使用,好比 a["name"] = 'Sam', 尤爲是屬性是數字字符串的時候,這時它會把字符串轉化爲數字,做爲數組的元素
let a = []; a['5'] = 5; console.log(a.length) // 6
類型轉化
首先要記住的是,Js中的類型轉化,它獲得的結果永遠是基本類型,也就能夠分爲兩種狀況,基本類型和基本類型之間的轉化,引用類型轉化爲基本類型,不可能出現基本類型轉化爲引用類型。類型轉化出現最多就是轉化成number, string, 和boolean. 這就是說,咱們在學習類型轉化的時候,也要分爲兩種狀況去學,好比轉化成string, 基本類型是怎麼轉化string的,引用類型是怎麼轉化成string的。