衆所周知,JavaScript 是一門弱類型語言,不對變量進行類型強制,變量能夠隨時持有任何類型的值,因此在 JavaScript 中,類型對於咱們開發人員來講能夠理解爲值的內部特徵,類型定義了值的行爲,以使其可以區別於其餘值。javascript
JavaScript 中共有七種內置數據類型,包括基本類型和對象類型。html
基本類型分爲如下六種:java
string
(字符串)boolean
(布爾值)number
(數字)symbol
(符號)null
(空值)undefined
(未定義)string
、number
、boolean
和 symbol
這四種類型統稱爲原始類型(Primitive),表示不能再細分下去的基本類型;symbol
表示獨一無二的值,經過 Symbol
函數調用生成,因爲生成的 symbol
值爲原始類型,因此 Symbol
函數不能使用 new
調用;null
和 undefined
一般被認爲是特殊值,這兩種類型的值惟一,就是其自己。git
對象類型( object
)也稱引用類型,以此和 JavaScript 的基本類型區分開來。對象在邏輯上是屬性的無序集合,是存放各類值的容器。對象值存儲的是引用地址,因此和基本類型值不可變的特性不一樣,對象值是可變的。github
聲明一個對象一般有如下幾種方式:數組
const obj = {} // 字面量形式,推薦
const obj = new Object() // new調用
const obj = Object() // 與new調用相同
cosnt obj = Object.create(null) // 空對象
複製代碼
咱們知道對象擁有屬性和方法。但好比字符串這種基本類型值不屬於對象爲何還擁有屬性和方法呢?實際上在引用字符串的屬性或方法時,會經過調用 new String()
的方式轉換成對象,該對象繼承了字符串的方法來處理屬性的引用,一旦引用結束,便會銷燬這個臨時對象,這就是包裝對象的概念。bash
不只僅只是字符串有包裝對象的概念,數字和布爾值也有相對應的 new Number()
和 new Boolean()
包裝對象。null
和 undefined
沒有包裝對象,訪問它們的屬性會報類型錯誤。函數
字符串、數字和布爾值經過構造函數顯式生成的包裝對象,既然屬於對象,和基本類型的值必然是有區別的,這點能夠經過 typeof
檢測出來。post
typeof 'seymoe' // 'string'
typeof new String('seymoe') // 'object'
複製代碼
咱們常常聽到諸如「 JavaScript 中一切皆是對象」的論斷,而且可以指出部分理由(或者說誤導性假象):學習
typeof null
結果是 object
但通過上述的內容,咱們應該很容易反駁「 JavaScript 中一切皆是對象」這一錯誤的論斷。
上文中咱們瞭解了 JavaScript 中的數據類型,那麼如何去判斷一個值屬於什麼數據類型呢?
判斷一個值屬於那種數據類型共有三種方式,分別爲 typeof
、instanceof
和 Object.prototype.toString()
,咱們分別來看。
通常經過 typeof
操做符來判斷一個值屬於哪一種基本類型。
typeof 'seymoe' // 'string'
typeof true // 'boolean'
typeof 10 // 'number'
typeof Symbol() // 'symbol'
typeof null // 'object' 沒法斷定是否爲 null
typeof undefined // 'undefined'
複製代碼
根據以上能夠看出,只有 null
的斷定會有偏差。
若是使用 typeof
操做符對對象類型及其子類型,譬如函數(可調用對象)、數組(有序索引對象)等進行斷定,則除了函數都會獲得 object
的結果。
typeof {} // 'object'
typeof [] // 'object'
typeof(() => {}) // 'function'
複製代碼
因爲沒法得知一個值究竟是數組仍是普通對象,顯然經過 typeof
判斷具體的對象子類型遠遠不夠。
經過 instanceof
操做符也能夠對對象類型進行斷定,其原理就是測試構造函數的 prototype
是否出如今被檢測對象的原型鏈上。
[] instanceof Array // true
({}) instanceof Object // true
(()=>{}) instanceof Function // true
複製代碼
注意:instanceof
也不是萬能的。
舉個例子:
let arr = []
let obj = {}
arr instanceof Array // true
arr instanceof Object // true
obj instanceof Object // true
複製代碼
在這個例子中,arr
數組至關於 new Array()
出的一個實例,因此 arr.__proto__ === Array.prototype
,又由於 Array
屬於 Object
子類型,即 Array.prototype.__proto__ === Object.prototype
,因此 Object
構造函數在 arr
的原型鏈上。因此 instanceof
仍然沒法判斷優雅的判斷一個值到底屬於數組仍是普通對象。
還有一點,可能有人會說 Object.prototype.__proto__ === null
,豈不是說 arr instanceof null
也應該爲 true
,這個語句其實會報錯提示右側參數應該爲對象,這也印證 typeof null
的結果爲 object
真的只是個 bug 。
Object.prototype.toString()
能夠說是斷定 JavaScript 中數據類型的終極解決方法了,具體用法請看如下代碼:
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(() => {}) // '[object Function]'
Object.prototype.toString.call('seymoe') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(Symbol()) // '[object Symbol]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(Math) // '[object Math]'
Object.prototype.toString.call(new Set()) // '[object Set]'
Object.prototype.toString.call(new WeakSet()) // '[object WeakSet]'
Object.prototype.toString.call(new Map()) // '[object Map]'
Object.prototype.toString.call(new WeakMap()) // '[object WeakMap]'
複製代碼
咱們能夠發現該方法在傳入任何類型的值都能返回對應準確的對象類型。用法雖簡單明瞭,但其中有幾個點須要理解清楚:
Object.prototype.toString()
方法獲得對象內部屬性 [[Class]]
null
和 undefined
可以輸出結果是內部實現有作處理將值從一種類型轉換爲另外一種類型被稱爲「類型轉換」,在 JavaScript 中類型轉換都屬於強制類型轉換。更進一步,咱們能夠借用《You Don't Know JS》做者在中卷提到的觀點,將強制類型轉換分爲隱式強制類型轉換和顯式強制類型轉換。某些操做符產生的反作用等不明顯的轉換就是隱式轉換,咱們可以從代碼中看到哪些地方進行了轉換就是顯式轉換。
let a = 10
let b = a + '' // 隱式強制類型轉換
var c = String(a) // 顯式強制類型轉換
複製代碼
上述代碼中,對於變量 b
來講,a
被強制轉換爲字符串類型與 ''
拼接,這個過程是「隱式」的,而對於變量 c
而言,主動調用 String
構造函數進行類型轉換是「顯式」的。但隱式和顯式仍然是相對的,若是你本身清楚數字與字符串相加,數字會被強制轉換爲字符串這個規則,那麼它就是顯式的,反之同理。
JavaScript 中,強制類型轉換老是會返回基本類型的值,好比字符串、數字、布爾值,不會返回對象和函數。
ES規範定義了一些抽象操做(即僅供內部使用的操做)和轉換規則來進行強制類型轉換,ToString 抽象操做就負責處理非字符串到字符串的強制類型轉換。
轉換規則:
null
轉換爲 'null'
undefined
轉換爲 undefined
true
轉換爲 'true'
,false
轉換爲 'false'
toString()
方法,不然返回內部屬性 [[Class]]
,如上文提到的 [object Object]
toString()
被從新定義的則相應調用返回結果String(null) // 'null'
String(undefined) // 'undefined'
String(true) // 'true'
String(1) // '1'
String(-1) // '-1'
String(0) // '0'
String(-0) // '0'
String(Math.pow(1000,10)) // '1e+30'
String(Infinity) // 'Infinity'
String(-Infinity) // '-Infinity'
String({}) // '[object Object]'
String([1,[2,3]]) // '1,2,3'
複製代碼
ToNumber 抽象操做負責處理非數字類型轉換爲數字類型。
轉換規則:
null
轉換爲 0
undefined
轉換爲 NaN
true
轉換爲 1
,false
轉換爲 0
NaN
爲了將值轉換爲基本類型值,規範定義了 ToPrimitive
內部操做,該操做首先檢測該值是否存在 valueOf()
方法,有且返回的值爲基本類型值則用此值返回或繼續轉換,沒有則檢測是否存在 toString()
方法,有且返回基本類型值則用此值返回或繼續轉換,沒有則報錯。
ToBoolean 抽象操做負責處理非布爾類型轉換爲布爾類型。
轉換規則:
null
、undefined
、false
、+0
、-0
、NaN
和 ''
JavaScript 中的數據類型總共只有七種,包括六種基本類型和對象類型,對象類型擁有不少子類型,也能夠說是 JavaScript 的內置對象。判斷一個值屬於那種數據類型有三種方式。JavaScript 中的數據類型轉換隻會返回基本類型值,因此基本存在轉換爲字符串、數字和布爾值三種狀況,轉換的更多具體細節,本文不作討究。
寫做是一個學習的過程,嘗試寫這個系列也主要是爲了鞏固 JavaScript 基礎,並嘗試理解其中的一些知識點,以便能靈活運用。若是有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝!
整個系列會持續更新,不會完結。