字數:1871
閱讀時間:5分鐘
引自MDN:
最新的 ECMAScript 標準定義了 7 種資料型別:
至今,JS中共上述7種資料型別。這裡需要注意,不要將js的內建物件:Date、Array等與資料型別混淆了,這些內建物件和我們自己建立的物件統一屬於Object型別。
6中原始型別的值都無法改變。舉個栗子,數值1
,我們是無法將他改變成2
的;字串的變化實質上也是產生了一個新的字串,舊的字串仍然不變。由於這種特性,js會將其存至棧中,按值訪問。而引用型別Object內容是可變的,而且大小不固定,所以將它存入堆中,通過地址引用的方式呼叫。
Boolean型別:表示邏輯,取值true
、false
。
Number型別:表示數字,和其他語言不同,js只有一種數字型別,是基於IEEE 754標準的雙精度64位的值,取值範圍(-2^63 - 1 至 2^63 - 1)。此外還有一些特殊識別符號:Infinity、-Infinity、NaN。
String型別:表示字串,由字元(2個位元組)組成的一組資料,因此它也具有陣列的可遍歷、擁有長度屬性等特性。
Symbol型別:表示符號型別,ES6新增的資料型別,表示一個唯一值,一般作為物件的key值或者列舉之用,非常適合消除魔法字串。
Null型別:表示空值,可以理解為一個尚未建立的物件。它雖然是空值,但是卻是一個物件,而且Object物件是繼承自它,所以它可以說才是真正的物件始祖。
注意:雖然null是一個物件,但是其中的屬性都是不可訪問的,因此,我們是無法通過程式碼獲取它的屬性的。
Undefined型別:表示未定義,一個沒有定義的變數或者沒有賦予初始值的物件的值就是undefined
。這裡不要與Null
混淆,它不是一個物件。
null === undefined; //false
null == undefined; //true
null === null; //true
undefined == undefined; //true
複製程式碼
Object型別:表示物件。在電腦科學中, 物件是指記憶體中的可以被識別符號引用的一塊區域。在JS中,物件可以被看做是一組屬性的集合。JS中以Object
和Function
兩個物件為基礎,衍生出了現在百花齊放的各種物件,JS的繼承、原型等都在這個基礎上實現的。
型別判斷
由於js弱型別的機制,變數的型別需要我們自己判斷。江湖上出現了各種判斷方法,下面我們來總結一下。
1.typeof
MDN上推薦的方法。
let str = 'string';
let pNum = 11;
let bRt = true;
let pSymbol = Symbol('symbol');
let pObj = {};
let pArray = [];
let fun = function () {};
//typeof
console.log('字串', typeof str); //string
console.log('數字', typeof pNum); //number
console.log('布林', typeof bRt); //boolean
console.log('符號', typeof pSymbol); //symbol
console.log('null', typeof null); //object
console.log('undefined', typeof undefined); //undefined
console.log('物件', typeof pObj); //object
console.log('陣列', typeof pArray); //object
console.log('函式', typeof fun); //function
複製程式碼
如上執行結果,對於原始型別(除了null以外),輸出結果沒問題。但是對於引用型別,輸出結果只會是object
、function
,這並非我們預期的結果。
typeof
輸出的結果包含以下7種:number、boolean、string、symbol、undefined、object、function。
2.instanceof
這種方式只能判斷擁有原型的物件,並且只能判斷比較的兩個物件之間是否屬於例項關係(包括繼承),不能獲取型別。
console.log('物件', pObj instanceof Object); //true
console.log('陣列是否陣列', pArray instanceof Array); //true
console.log('陣列是否物件', pArray instanceof Object); //true
console.log('函式是否函式', fun instanceof Function); //true
console.log('函式是否物件', fun instanceof Object); //true
複製程式碼
需要注意,它會去原型鏈上去尋找匹配項,例如:pArray instanceof Object
結果也是true。該方法用作判斷變數是否是某個類的例項非常有效。但是需要注意,這裡的比對預設都是在同一個全域性環境下比對的。也就是說,在同一個frame下,我們才能得到正確結果。如果在frame1下去判斷一個變數是否屬於frame2的Object,只會得到false結果。
3.constructor或__proto__
console.log('construct');
console.log('字串', str.construct === String.construct); //true
// console.log('數字', typeof pNum); //數字沒有construct
console.log('布林', bRt.construct === Boolean.construct); //true
// console.log('符號', typeof pSymbol); //symbol沒有construct
// console.log('null', typeof null); //null無法訪問construct屬性
// console.log('undefined', typeof undefined); //undefined無法訪問construct屬性
console.log('物件', pObj.construct === Object.construct); //true
console.log('陣列', pArray.construct === Array.construct); //true
console.log('函式', fun.construct === Function.construct); //true
console.log('__proto__');
console.log('字串', str.__proto__ === String.prototype); //true
// console.log('數字', typeof pNum); //數字沒有prototype
console.log('布林', bRt.__proto__ === Boolean.prototype); //true
// console.log('符號', typeof pSymbol); //symbol沒有prototype
// console.log('null', typeof null); //null無法訪問prototype屬性
// console.log('undefined', typeof undefined); //undefined無法訪問prototype屬性
console.log('物件', pObj.__proto__ === Object.prototype); //true
console.log('陣列', pArray.__proto__ === Array.prototype); //true
console.log('函式', fun.__proto__ === Function.prototype); //true
複製程式碼
原理同2,只是不會再去原型鏈上查詢了,這裡固定只對比當前物件的例項。
4.toString
console.log('字串', Object.prototype.toString.call(str)); //[object String]
console.log('數字', Object.prototype.toString.call(pNum)); //[object Number]
console.log('布林', Object.prototype.toString.call(bRt)); //[object Boolean]
console.log('符號', Object.prototype.toString.call(pSymbol)); //[object Symbol]
console.log('null', Object.prototype.toString.call(null)); //[object Null]
console.log('undefined', Object.prototype.toString.call(undefined)); //[object Undefined]
console.log('物件', Object.prototype.toString.call(pObj)); //[object Object]
console.log('陣列', Object.prototype.toString.call(pArray)); //[object Array]
console.log('函式', Object.prototype.toString.call(fun)); //[object Function]
console.log('日期', Object.prototype.toString.call(new Date())); //[object Date]
console.log('window', Object.prototype.toString.call(window)); //[object HTMLDocument]
console.log('document', Object.prototype.toString.call(document)); //[object global]
複製程式碼
Object中定義的toString方法,返回的是當前物件的內部屬性[[Class]],結果格式為[object Xxx],其中Xxx就是我們判斷資料型別的依據,也是內建物件的字串。
看一下優秀的框架是怎麼做的
JQuery
function toType( obj ) {
if ( obj == null ) {
return obj + "";
}
// Support: Android <=2.3 only (functionish RegExp)
return typeof obj === "object" || typeof obj === "function" ?
class2type[ toString.call( obj ) ] || "object" :
typeof obj;
}
複製程式碼
原始型別使用typeof,引用型別使用toString。
AngularJs
function isNumber(value) {return typeof value === 'number';}
function isDate(value) {
return toString.call(value) === '[object Date]';
}
複製程式碼
也是一樣,原始型別使用typeof,引用型別使用toString。
這裡其實toString能夠完成typeof的所有任務,不知為何以上兩個框架會混用。私自猜測可能是因為typeof使用起來更為簡潔一點,所以會優先使用typeof。
總結
①boolen、number、string、symbol、function可通過typeof或toString方式判斷。
②null、undefined直接通過 ===
運算子判斷。
③js內建物件,如:Object、Function、Date、Regex等通過toString方式判斷。
④自定義類和相應繼承類,通過 instanceof判斷。
參考:
歡迎關注我的微信公眾號: