歡迎Star:github.com/FatGe/FatGe…html
JS 的基本數據類型有 Number
,String
,Boolean
,Symbol
,Null
,Undefined
,六種數據類型。一種引用類型 object
。java
數值,根據 ECMAScript 標準,JavaScript 中只有一種數字類型:基於 IEEE 754 標準的雙精度 64 位二進制格式的值(-(263 -1) 到 263 -1)。它並無爲整數給出一種特定的類型。node
除了可以表示浮點數外,還有一些帶符號的值:+Infinity
,-Infinity
和 NaN
(非數值,Not-a-Number)。git
對應 lodash 中的檢測函數有github
isNumber
檢查 value
是不是原始 Number
數值型 或者 對象;isInteger
檢查 value
是否爲一個整數;isNaN
檢測 value
是否爲 NaN
;isFinite
檢測 value
是不是原始有限數值。isNumber
function isNumber(value) {
return typeof value == 'number' ||
(isObjectLike(value) && getTag(value) == '[object Number]')
}
複製代碼
typeof
操做符能夠返回一個字符串,表示未經計算的操做數的類型。對於 Number、String、Boolean、Undefined、String 能夠很明確的獲得它的類型。web
那麼 lodash 爲何還要添加 (isObjectLike(value) && getTag(value) == '[object Number]')
?數組
緣由在於,JS 中也容許咱們以以下形式建立一個數值數據結構
const value = new Number(1)
console.log(value) // log 1
console.log(typeof value) // log "object"
複製代碼
這時,單單只是使用 typeof
操做符就無法判斷 value
的類型是否爲數值。因此要結合如下兩個函數來判斷,value
是否爲 object
而後再經過過 toString()
來獲取每一個對象的類型。函數
function getTag(value) {
if (value == null) {
return value === undefined ? '[object Undefined]' : '[object Null]'
}
return Object.prototype.toString.call(value)
}
function isObjectLike(value) {
return typeof value == 'object' && value !== null
}
複製代碼
Object.prototype.toString.call
每一個對象都有一個toString()
方法,當該對象被表示爲一個文本值時,或者一個對象以預期的字符串方式引用時自動調用。ui
isInteger
function isInteger(value) {
return
typeof value == 'number'
&& value == toInteger(value);
}
複製代碼
檢查 value
是否爲一個整數,判斷是否 value
的類型是否爲數值,而且是否與 Int 型相同。其取整過程以下
function toInteger(value) {
var result = toFinite(value),
remainder = result % 1;
return result === result ?
(remainder ? result - remainder : result) : 0;
}
複製代碼
isNaN
檢查 value
是不是 NaN
。
function isNaN(value) {
return isNumber(value) && value != +value;
}
複製代碼
與 ES 2015 的 isNaN
不一樣的是,對於 undefined
,{}
,原生的結果是 true
,而 lodash 爲 false
。這是由於若是isNaN
函數的參數不是Number
類型, isNaN
函數會首先嚐試將這個參數轉換爲數值,而後纔會對轉換後的結果是不是NaN
進行判斷。
// js native isNaN
var isNaN = function(value) {
var n = Number(value);
return n !== n;
};
複製代碼
可是不管是 ES 2015 仍是 lodash,它們本質上都是利用 x != x
來判斷 NaN
。
isFinite
檢查 value
是不是原始有限數值。
function isFinite(value) {
return typeof value == 'number'
&& nativeIsFinite(value);
}
複製代碼
利用原生的 isFinite
結合 typeof
判斷數字是否爲有限值。
String 類型用於表示由零或多個16 位Unicode 字符組成的字符序列,即字符串。用於保存能夠以文本形式表示的數據很是有用。
值得注意的是,不僅僅要注意基本字符串,還須要注意字符串對象,字符串字面量 (經過單引號或雙引號定義) 和 直接調用 String 方法(沒有經過 new 生成字符串對象實例)的字符串都是基本字符串。
JavaScript會自動將基本字符串轉換爲字符串對象,只有將基本字符串轉化爲字符串對象以後纔可使用字符串對象的方法。
與以前的 number 相似,利用構造函數 String
建立的字符串是一個 object
const s_prim = "foo";
const s_obj = new String(s_prim);
console.log(typeof s_prim); // Logs "string"
console.log(typeof s_obj); // Logs "object"
複製代碼
因此檢測字符串,除了基本字符串之外還要注意字符串對象。
function isString(value) {
const type = typeof value
return
type == 'string' ||
(type == 'object'
&& value != null
&& !Array.isArray(value)
&& getTag(value) == '[object String]')
}
複製代碼
能夠利用 typeof
檢測基本字符串,對於模板字符串採用了以前介紹的方案 getTag
來獲取 value
的類型。
Boolean 類型是ECMAScript 中使用得最多的一種類型,該類型只有兩個字面值:true
和 false
。一樣也須要區分基本的 Boolean 類型以及 Boolean 對象。
function isBoolean(value) {
return
value === true || value === false ||
(isObjectLike(value)
&& getTag(value) == '[object Boolean]')
}
複製代碼
大部分在以前都已經涉及到了,這裏出現了 isObjectLike
,那麼它是作什麼的。
function isObjectLike(value) {
return typeof value == 'object' && value !== null
}
複製代碼
原來只是檢測是不是一個非 null
的對象。
ES6 引入了一種新的原始數據類型Symbol
,表示獨一無二的值。Symbol 值經過Symbol
函數生成。
function isSymbol(value) {
const type = typeof value
return type == 'symbol' ||
(isObjectLike(value) &&
getTag(value) == '[object Symbol]')
}
複製代碼
會發現 (isObjectLike(value) && getTag(value) == '[object Symbol]')
,也對 Symbol 對象進行檢測,可是若是直接 new Symbol
會 log 出 TypeError
。
那麼 lodash 爲何要對其進行檢測,原來是建立一個顯式包裝器對象從 ECMAScript 6 開始再也不被支持,如今能夠利用以下代碼來模擬,雖然沒什麼用。
const sym = Symbol("foo");
typeof sym; // "symbol"
const symObj = Object(sym);
typeof symObj; // "object"
複製代碼
Undefined 類型只有一個值,即特殊的 undefined
。在使用 let
或 var
聲明變量但未對其加以初始化時,這個變量的值就是 undefined
。
function isUndefined(value) {
return value === undefined;
}
複製代碼
Null 類型是隻有一個值的數據類型,這個特殊的值是 null
。與 undefined
不一樣的是,它是一個字面量,而 undefined
是全局對象的一個屬性。
從邏輯角度來看,null 值表示一個空對象指針,null
是表示缺乏的標識,指示變量未指向任何對象。而這也正是使用typeof 操做符檢測null 值時會返回"object"的緣由。
對其的判斷也很是的簡單,只須要
function isNull(value) {
return value === null
}
複製代碼
固然你也可使用
console.log(Object.prototype.toString.call(null))
// [object Null]
複製代碼
以上是基本數據類型的判斷,總結一下,主要是利用 typeOf
以及 Object.prototype.toString
,還有一些特殊值的特性。下面開始分析引用類型 Object
引用類型的值(對象)是引用類型的一個實例。在ECMAScript 中,引用類型是一種數據結構,用於將數據和功能組織在一塊兒。具體的有 Object
、Array
、Date
、Error
、RegExp
、Function
,還有ES2015 引入 Set
、Map
、WeakSet
、WeakMap
。
ECMAScript 中的對象其實就是一組數據和功能的集合。它有一個很重要的用途,就是在 JavaScript 中的全部對象都來自 Object
;全部對象從Object.prototype
繼承方法和屬性,儘管它們可能被覆蓋。即在ECMAScript 中,Object 類型是全部它的實例的基礎。
因此 Lodash 去判斷 value
是否爲 Object
時,只使用了 typeOf
操做便可。
function isObject(value) {
const type = typeof value
return value != null &&
(type == 'object' || type == 'function')
}
複製代碼
Function 構造函數 建立一個新的Function對象。 在 JavaScript 中, 每一個函數實際上都是一個Function對象。
function isFunction(value) {
if (!isObject(value)) {
return false
}
const tag = getTag(value)
return tag == '[object Function]' ||
tag == '[object AsyncFunction]' ||
tag == '[object GeneratorFunction]' ||
tag == '[object Proxy]'
}
複製代碼
有個問題,typeOf
能夠檢測 Function對象的類型爲 Function
, 那爲何還須要 Object.prototype.toString
呢?
// in Safari 9 which returns 'object' for typed arrays and other constructors.
Array 在 ECMAScript 中表明數組,它的每一項能夠保存任何類型的數據。
對它的常規檢測就是 Array.isArray
,Lodash 也是使用這個 API,若是須要 Polyfill 方案的話,可使用
// plan 1
Object.prototype.toString.call(value) === '[object Array]'
// plan 2
value.constructor === Array
複製代碼
以前還有 value instanceof Array
會什麼問題麼?
在存在不一樣全局變量的環境,經過語義
instanceof
檢測數組的時候,value instanceof Array
只有當value
是由該頁面的原始Array
構造函數建立的數組時才能正常工做。
ECMAScript 中的 Date 類型是在早期Java 中的java.util.Date 類基礎上構建的。
const nodeIsDate = nodeTypes && nodeTypes.isDate
const isDate = nodeIsDate
? (value) => nodeIsDate(value)
: (value) => isObjectLike(value) && getTag(value) == '[object Date]'
複製代碼
Lodash 分爲兩個環境來處理這個問題,若是是 Node 就利用 util.types.isDate(value)
來檢測,若是是在遊覽器,就仍是經過 Object.prototype.toString
來判斷。
ES2015 提供了新的數據結構 Set。它相似於數組,可是成員的值都是惟一的,沒有重複的值。
const isSet = nodeIsSet
? (value) => nodeIsSet(value)
: (value) => isObjectLike(value) && getTag(value) == '[object Set]'
複製代碼
一樣的還有 Map
const isMap = nodeIsMap
? (value) => nodeIsMap(value)
: (value) => isObjectLike(value) && getTag(value) == '[object Map]'
複製代碼
WeakSet 結構與 Set 相似,也是不重複的值的集合。可是,它與 Set 有兩個區別。
function isWeakSet(value) {
return isObjectLike(value) && getTag(value) == '[object WeakSet]'
}
複製代碼
也是利用 Object.prototype.toString
,一樣還有 WeakMap
function isWeakMap(value) {
return isObjectLike(value) && getTag(value) == '[object WeakMap]'
}
複製代碼
當運行時錯誤產生時,Error的實例對象會被拋出。
function isError(value) {
if (!isObjectLike(value)) {
return false
}
const tag = getTag(value)
return tag == '[object Error]' ||
tag == '[object DOMException]' ||
(typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value))
}
複製代碼
有以前一致的 Object.prototype.toString
依然能夠用來判斷對象是不是一個 Error,除此以外,若是對象知足如下條件,也能夠被視爲一個 Error
message
、name
屬性,且值爲 string
;Object
構造函數建立,或者 [[Prototype]]
爲 null
。那麼如何檢測普通對象呢?
function isPlainObject(value) {
if (!isObjectLike(value) || getTag(value) != '[object Object]') {
return false
}
if (Object.getPrototypeOf(value) === null) {
return true
}
let proto = value
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(value) === proto
}
複製代碼
主要是利用 Object.getPrototypeOf()
方法返回指定對象的原型(內部[[Prototype]]
屬性的值),同時和 value
自己的 [[Prototype]]
作判斷。