玩轉 JavaScript 之數據類型

概述

衆所周知,JavaScript 是一門弱類型語言,不對變量進行類型強制,變量能夠隨時持有任何類型的值,因此在 JavaScript 中,類型對於咱們開發人員來講能夠理解爲值的內部特徵,類型定義了值的行爲,以使其可以區別於其餘值javascript

JavaScript 中共有種內置數據類型,包括基本類型對象類型html

基本類型

基本類型分爲如下六種:java

  • string(字符串)
  • boolean(布爾值)
  • number(數字)
  • symbol(符號)
  • null(空值)
  • undefined(未定義)

stringnumberbooleansymbol 這四種類型統稱爲原始類型(Primitive),表示不能再細分下去的基本類型;symbol 表示獨一無二的值,經過 Symbol 函數調用生成,因爲生成的 symbol 值爲原始類型,因此 Symbol 函數不能使用 new 調用;nullundefined 一般被認爲是特殊值,這兩種類型的值惟一,就是其自己。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() 包裝對象。nullundefined 沒有包裝對象,訪問它們的屬性會報類型錯誤。函數

字符串、數字和布爾值經過構造函數顯式生成的包裝對象,既然屬於對象,和基本類型的值必然是有區別的,這點能夠經過 typeof 檢測出來。post

typeof 'seymoe'                 // 'string'
typeof new String('seymoe')     // 'object'
複製代碼

一切皆是對象?

咱們常常聽到諸如「 JavaScript 中一切皆是對象」的論斷,而且可以指出部分理由(或者說誤導性假象):學習

  • 所謂例如字符串、數字等基本類型值「擁有」屬性和方法
  • typeof null 結果是 object
  • 可調用的函數也屬於對象(子類型)
  • ......

但通過上述的內容,咱們應該很容易反駁「 JavaScript 中一切皆是對象」這一錯誤的論斷。

數據類型斷定

上文中咱們瞭解了 JavaScript 中的數據類型,那麼如何去判斷一個值屬於什麼數據類型呢?

判斷一個值屬於那種數據類型共有三種方式,分別爲 typeofinstanceofObject.prototype.toString(),咱們分別來看。

typeof

通常經過 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

經過 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()

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]]
  • 傳入原始類型卻可以斷定出結果是由於對值進行了包裝
  • nullundefined 可以輸出結果是內部實現有作處理

類型轉換

將值從一種類型轉換爲另外一種類型被稱爲「類型轉換」,在 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 轉換爲 1false 轉換爲 0
  • 字符串轉換時遵循數字常量規則,轉換失敗返回 NaN
  • 對象類型會被轉換爲相應的基本類型值,若是獲得的值類型不是數字,則遵循以上規則強制轉換爲數字

爲了將值轉換爲基本類型值,規範定義了 ToPrimitive 內部操做,該操做首先檢測該值是否存在 valueOf() 方法,有且返回的值爲基本類型值則用此值返回或繼續轉換,沒有則檢測是否存在 toString() 方法,有且返回基本類型值則用此值返回或繼續轉換,沒有則報錯。

轉換爲布爾值

ToBoolean 抽象操做負責處理非布爾類型轉換爲布爾類型。

轉換規則:

  • 能夠被強制強制類型轉換爲false的值:nullundefinedfalse+0-0NaN''
  • 假值列表之外的值都是真值

總結

JavaScript 中的數據類型總共只有七種,包括六種基本類型和對象類型,對象類型擁有不少子類型,也能夠說是 JavaScript 的內置對象。判斷一個值屬於那種數據類型有三種方式。JavaScript 中的數據類型轉換隻會返回基本類型值,因此基本存在轉換爲字符串、數字和布爾值三種狀況,轉換的更多具體細節,本文不作討究。

參考資料

玩轉 JavaScript 系列

寫做是一個學習的過程,嘗試寫這個系列也主要是爲了鞏固 JavaScript 基礎,並嘗試理解其中的一些知識點,以便能靈活運用。若是有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝!

整個系列會持續更新,不會完結。

全目錄

1. 玩轉 JavaScript 之 數據類型

相關文章
相關標籤/搜索