ECMAScript5
中有五種基本數據類型:Undefined,Null,Boolean,Number,String
,以及一種複雜(引用類型)數據類型:Object
,Object
中還細分了不少具體的類型,好比:Array, Function, Date
等等;ECMAScript6
中又新增了一種Symbol
類型。es6
typeof
操做符typeof
是操做符,而不是函數,它可能返回:編程
"undefined"
:若是這個值未定義"boolean"
:若是這個值是布爾值"string"
:若是這個值是字符串值"number"
:若是這個值是數值"object"
:若是這個值是對象或者null
"function"
:若是這個值是函數"symbol"
:若是這個值是Symbol
值函數在ECMAScript
中是對象,不是一種數據類型;可是函數卻也有一些特殊的屬性,因此經過typeof
來區分對象和函數是有必要的安全
Undefined
類型Undefined
類型只有一個值 —— undefined
,當一個變量僅聲明而未初始化時,這個變量的值就是undefined
(當一個變量未聲明(未定義)時,若是訪問它將會報錯)函數
var a; let b; console.log(a,b);//undefined undefined console.log(c);//ReferenceError: c is not defined
在ES6
以前,typeof
是一個百分之百安全的操做,由於即便是對於未聲明的變量,typeof
會返回"undefined"
,而不會報錯。測試
可是ES6
引入了let,const
來聲明變量,這兩個命令沒有聲明提高,必定要在聲明語句以後才能使用,不然就會報錯;並且let,const
還存在暫時性死區:this
只要塊級做用域內存在let或const命令,它所聲明的變量就「綁定」(binding)這個區域,再也不受外部的影響。
ES6 明確規定,若是區塊中存在let或const命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域,凡是在聲明以前就使用這些變量,就會報錯
let tmp = 123; if (true) { tmp = 'abc'; // ReferenceError: tmp is not defined let tmp; }
上面的代碼中存在全局變量tmp
,可是塊級做用域內let
又聲明瞭一個局部變量tmp
,致使後者綁定這個塊級做用域,因此在let
聲明變量前,對tmp
賦值會報錯。編碼
因此「暫時性死區」也意味着typeof
再也不是一個百分之百安全的操做,這樣的設計是爲了讓你們養成良好的編程習慣,變量必定要在聲明以後使用,不然就報錯spa
Null
類型Null
類型只有一個值 —— null
,從邏輯角度來看,null
表示一個空對象指針,這也是用typeof
操做符檢測null
會返回"object"
的緣由。prototype
undefined
值是派生自null
值的,因此undefined == null
會返回true
,可是它們二者的用途徹底不一樣。設計
只要意在保存對象的變量尚未真正保存對象,就應該讓該變量保存null
值,這樣作不只能夠體現null
做爲空指針對象的慣例,還有助於區分null
和undefined
。
Boolean
類型Boolean
類型有兩個字面值,表示真的true
和表示假的false
;ECMAScript
中全部類型的值都有與這兩個Boolean
值等價的值,能夠經過Boolean()
函數轉換
數據類型 | 轉換爲true的值 | 轉換爲false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | ""空字符串 |
Number | 任何非零數字值(包括無窮大) | 0和NaN |
Object | 任何對象 | null |
Undefined | 不適用 | undefined |
Symbol | 任何 | 不適用 |
Number
類型Number
類型的數值字面量格式有八進制(嚴格模式下使用八進制將會報錯)、十進制和十六進制,其中八進制字面值的第一位必須爲0
,十六進制前兩位必須爲0x
。在進行算術計算時,八進制和十六進制都會轉換爲十進制。
Number
類型使用IEEE754
標準定義的64位浮點數表示,存儲爲8字節,使用時不區分整數與浮點數,1與1.0是同樣的,存儲狀況以下:
其中尾數位即有效數字部分,IEEE754
規定,有效數字第一位默認老是1,即有效數字老是1.xx...xx的形式,其中第一位不進行存儲,而xx..xx的部分保存在64位浮點數之中,最長可能爲52位。所以,JavaScript
實際提供的有效數字最長爲53個二進制位,一個數字能夠表示爲:
(-1)^符號位 * 1.xx...xx * 2^指數位
有效數字精度最多隻能到53個二進制位,這意味着,絕對值小於2的53次方的整數,即在-(Math.pow(2, 53) - 1
到 Math.pow(2, 53) - 1
範圍內的整數均可以精確表示(安全整數),而不在該範圍內的整數則會喪失精度。
es6
中增長了Number.MAX_SAFE_INTEGER
及Number.MIN_SAFE_INTEGER
來表示安全整數範圍的上下限,還增長了方法Number.isSafeInteger
來判斷是否處於安全整數範圍內。
浮點數的最高精度是17
位小數,可是計算時的精度遠遠不如整數,浮點數值計算會產生舍入偏差的問題,這是使用基於IEEE754
數值的浮點計算的通病,因此永遠不要測試某個特定的浮點數數值。
Number
類型的數值範圍是Number.MIN_VALUE ~ Number.MAX_VALUE
,超出這個範圍的值爲Infinity
,可使用isFinite()
函數來判斷數值是否在範圍內。
Number
類型有一個特殊的值——NaN(Not a Number)
他表示一個原本要返回數值的操做數卻未返回數值的狀況,NaN
是數字類型 可是不是數字,他有兩個特色
NaN
的操做都會返回NaN
NaN
與任何值都不相等,包括它本身0
處於0
返回NaN
,其餘的除以0
返回infinity
或-infinity
NaN
的布爾值是false
isNaN()
函數能夠判斷傳入的參數是否「不是數值」,判斷前會自動調用Number()
進行轉換,轉換後再進行判斷,任何不能轉換爲數值的值都會致使這個函數返回true
;這個函數也適用於對象,在基於對象調用它時,會先調用對象的valueOf()
方法,而後肯定該方法的返回值是否能夠轉換爲數值。若是不能,則基於這個返回值再調用toString()
方法,再測試返回值有如下幾種方法能夠把非數值轉換爲數值
Number()
函數
undefined
值,返回NaN
0
會忽略,若是字符串包含了除數值,0x
之外的字符將會返回NaN
valueOf()
方法,而後肯定該方法的返回值是否能夠轉換爲數值。若是不能,即返回值是NaN
,則基於這個返回值再調用toString()
方法,再去轉換返回的字符串值parseInt()
函數
NaN
。因此轉換空字符串返回NaN
ECMAScript 3
和ECMAScript 5
在解析八進制字面量字符時有分歧,ECMAScript 5
中的parseInt()
已經不具有解析八進制的能力,前導0
會被忽略,因此最好指定進制數,也就是第二個參數)parseFloat()
函數
NaN
。0
,它只解析十進制值,因此它只有一個參數。若是是十六進制會返回0
,由於十六進制的0x
,parseFloat()
函數只會解析到0
~
符號(按位非)
1
對於NaN
、Infinity
,應用位操做符會被當作0
來處理
console.log(~NaN);// -1 console.log(~Infinity);// -1
非數值應用位操做符時會先使用Number()
函數將該值轉換爲數值,在應用位操做符
console.log(~"12");// -13 console.log(~"w12");// -1
若是是對浮點數應用位操做符,將會對其取整(直接把小數點捨去的這種取整),再應用位操做符
console.log(~1.2);// -2 console.log(~-1.2);// 0
~~
符號(兩次按位非)
++
、--
,能夠轉換數據類型,是按Number()
函數來轉換的
++/--
後面的內容按Number
函數轉換,再加減var a = "0xf"; a++; console.lgo(a);// 16
+
、-
能夠轉換數據類型,將其餘的轉爲數字類型
Number()
函數來轉換的+
號前面沒有其餘東西時,+
字符串會按照Number()
函數來轉換字符串,其餘的時候是字符串鏈接-
轉換後,會在轉換後的數值前加上負號,因此都是用+
好來轉換String
類型String
類型表示由零個或多個16
位Unicode
字符組成的字符序列——字符串,JavaScript
建立的時候,Unicode
是一個16
位字符集,因此JavaScript
中的字符都是16
位的,採用UCS-2
編碼方式(關於Unicode
的知識能夠參見)
字符串是不可變的,一旦建立,值就不能改變;要改變就要先銷燬原來的字符串(銷燬過程在後臺完成),再用另外一個包含新值的字符串填充該變量
String
類型包含一些特殊的字符字面量,好比\n,\t,\b,\xnn,\unnnn
等,他們稱爲轉義序列,能夠出如今字符串的任意位置,將被當作一個字符來解析;可是若是包含雙字節字符,字符串將解析錯誤,length
也將返回錯誤的結果
var a = "Look this: \b"; var b = "Look this: \u20BB7"; console.log(a,a.length);//"Look this: " 12 console.log(b,b.length);//"Look this: 7" 13
爲了解決這個問題,ES6
中對字符的Unicode
表示法作了改進,只要將Unicode
碼點放入大括號,就能正確解讀該字符,可是length
屬性仍是返回錯誤,若想要正確的能夠經過Array.form(xx).length
var b = "Look this: \u{20BB7}"; console.log(b,b.length);//"Look this: 𠮷" 13 console.log(Array.form(b).length);// 12
有如下幾種方法能夠把非字符串值轉換爲字符串值
toString()
方法
null
和undefined
沒有這個方法String()
方法
null
和undefined
)toString
方法,就調用這個null
返回"null"
,是undefined
返回"undefined"
+
符號
Object
類型ECMAScript
中的對象是一組數據和功能的集合,Object
類型是全部它的實例的基礎,即Object
類型所具備的任何屬性和方法也存在於更具體的對象中
每一個Object
實例都具備如下屬性和方法
constructor
:保存着用於建立當前對象的函數(構造函數)
var s = "cc"; var b = true; console.log(s.constructor);//ƒ String() console.log(b.constructor);//ƒ Boolean()
hasOwnProperty(propertyName)
:檢查一個對象自身(不包括原型鏈)是否具備指定名稱的屬性。若是有,返回true
,不然返回false
,參數必須爲字符串prototypeObject.isPrototypeOf( object )
:檢查prototypeObject
是否存在於object
的原型鏈中propertyIsEnumerable
:檢查給定的屬性是否可以用for-in
語句來枚舉,參數必須爲字符串
false
,能夠理解爲它只是繼承了這個屬性可是沒有真的屬於他本身,因此就不能枚舉toLocalString
:返回對象的字符串表示,與執行環境的地區對應toString
:返回對象的字符串表示valueOf
:返回對象的字符串、數值或布爾值表示Symbol
類型這個類型表示獨一無二的值,經過Symbol()
函數生成,能夠做爲屬性名,凡是屬性名屬於 Symbol
類型,就都是獨一無二的,能夠保證不會與其餘屬性名產生衝突。
Symbol()
函數能夠接受一個字符串做爲參數,表示對Symbol
實例的描述,主要是爲了在控制檯顯示,或者轉爲字符串時,比較容易區分。若是Symbol()
的參數不是字符串,就會調用toString
方法,將其轉爲字符串,而後才生成一個 Symbol
值。注意,Symbol
函數的參數只是表示對當前 Symbol
值的描述,所以相同參數的Symbol
函數的返回值是不相等的。
let s1 = Symbol('foo'); let s2 = Symbol('foo'); s1 === s2 // false
Symbol
值不能與其餘類型的值進行運算,會報錯,在模板字符串中也不能使用Symbol
值;
let s = Symbol('My symbol'); "your symbol is " + s // TypeError: Cannot convert a Symbol value to a string `your symbol is ${s}` // TypeError: Cannot convert a Symbol value to a string s + 1 // TypeError: Cannot convert a Symbol value to a number
可是它能夠顯式轉換爲字符串值、布爾值,可是不能轉換爲數值
let s = Symbol('My symbol'); String(s) // "Symbol(My symbol)" s.toString() // "Symbol(My symbol)" Boolean(s) // true Number(s) // TypeError: Cannot convert a Symbol value to a number
Symbol
值能夠用於對象的屬性名,能夠能保證不會出現同名的屬性,此時不能用點運算符,只能用方括號:
const mySymbol = Symbol(); const a = {}; a.mySymbol = "Hello"; a[mySymbol] = "World!" console.log(a['mySymbol']); // "Hello" console.log(a[mySymbol]); // "World!"
由於點運算符後面老是字符串,因此不會讀取mySymbol
做爲標識名所指代的那個值,致使a
的屬性名其實是一個字符串,而不是一個 Symbol
值。
Symbol
做爲屬性名,該屬性不會出如今for...in
、for...of
循環中,也不會被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回。可是,它也不是私有屬性,有一個Object.getOwnPropertySymbols
方法,能夠獲取指定對象的全部 Symbol
屬性名。Reflect.ownKeys
方法能夠返回全部類型的鍵名,包括常規鍵名和 Symbol 鍵名。
Symbol.for
方法能夠作到從新使用同一個Symbol
值。它接受一個字符串做爲參數,而後搜索有沒有以該參數做爲名稱的 Symbol
值。若是有,就返回這個 Symbol
值,不然就新建並返回一個以該字符串爲名稱的 Symbol
值
let s1 = Symbol.for('foo'); let s2 = Symbol.for('foo'); s1 === s2 // true
Symbol.for()
與Symbol()
這兩種寫法,都會生成新的 Symbol
。它們的區別是:前者會被登記在全局環境中供搜索,後者不會
Symbol.for()
不會每次調用就返回一個新的 Symbol
類型的值,而是會先檢查給定的key
是否已經存在,若是不存在纔會新建一個值Symbol()
寫法沒有被登記,每次調用都會返回一個新的 Symbol
類型的值,每次的都是不一樣的值Symbol.for
爲 Symbol
值登記的名字,是全局環境的,能夠在不一樣的 iframe
或 service worker
中取到同一個值Symbol.for("bar") === Symbol.for("bar") // true Symbol("bar") === Symbol("bar") // false
Symbol.keyFor
方法返回一個已登記的 Symbol
類型值的key
,也就是返回使用Symbol.for
生成的Symbol
類型值的key
,若是沒有傳參數則返回"undefined"
;對於Symbol()
生成的Symbol
類型值返回undefined
let s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo" let s2 = Symbol.for(); Symbol.keyFor(s3) // "undefined" let s3 = Symbol("foo"); Symbol.keyFor(s3) // undefined
typeof 變量 //"undefined"/"boolean"/"number"/"string"/"object"/"function"/"symbol"
typeof
能夠正確檢測出Number, String, Boolean, Undefined, Symbol
類型,但Array, Null, Date, Reg, Error
所有被檢測爲Object
類型,也就是說不能檢測出Object
類型下的細分類型
變量 instanceof 類型 //true or false
instanceof
方法要求開發者明確地確認對象爲某特定類型,它能夠檢測Object
類型下的細分類型,便可以正確檢測出Array,Function,Date,Reg,Error
類型,以及使用new
操做符建立的Number, String, Boolean
類型(對於普通的字面量形式的Number, String, Boolean
沒法檢測)。
instanceof
沒法檢測Null, Undefined, Symbol
類型,老是會返回false
,因此使用instanceof
進行變量檢測時,須要首先判斷是不是Null, Undefined, Symbol
類型
instanceof
不能跨iframe
(每一個頁面的類型原生對象所引用的地址是不同的)
變量.constructor == 類型 //true or false
constructor
原本是原型對象上的屬性,指向其構造函數。可是根據實例對象尋找屬性的順序,若實例對象上沒有實例屬性或方法時,就去原型鏈上尋找,所以,實例對象也是能使用constructor
屬性的
constructor
能夠正確檢測Null, Undefined
以外的全部類型,包括Symbol
類型,Null, Undefined
沒有constructor
屬性
使用constructor
不是保險的,由於constructor
屬性是能夠被修改的,會致使檢測出的結果不正確
constructor
不能跨iframe
(每一個頁面的類型原生對象所引用的地址是不同的)
Object.prototype.toString.call(變量) == "[object 類型]" //true or false
Object.prototype.toString.call
的行爲:
[[Class]]
[[Class]]
這個屬性,返回一個相似於"[object Array]"
的字符串做爲結果call
能夠取得任何對象的內部屬性[[Class]]
,而後把類型檢測轉化爲字符串比較,以達到咱們的目的這個方法能夠檢測出全部的類型,包括Null,Undefined
、Object
下的細分類型以及Symbol
類型
jQuery
中$.type
的實現jQuery
就是用Object.prototype.toString.call
結合typeof
實現的
typeof
進行檢測typeof
返回"object"
或者"function"
時,再使用Object.prototype.toString.call
來檢測因此除了Object
和Function
,其餘的都是使用typeof
進行檢測