前端基礎(一):js資料型別

大司馬愛學習發表於2018-06-06

字數:1871

閱讀時間:5分鐘

引自MDN:

最新的 ECMAScript 標準定義了 7 種資料型別:

至今,JS中共上述7種資料型別。這裡需要注意,不要將js的內建物件:Date、Array等與資料型別混淆了,這些內建物件和我們自己建立的物件統一屬於Object型別。

6中原始型別的值都無法改變。舉個栗子,數值1,我們是無法將他改變成2的;字串的變化實質上也是產生了一個新的字串,舊的字串仍然不變。由於這種特性,js會將其存至棧中,按值訪問。而引用型別Object內容是可變的,而且大小不固定,所以將它存入堆中,通過地址引用的方式呼叫。

Boolean型別:表示邏輯,取值truefalse

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中以ObjectFunction兩個物件為基礎,衍生出了現在百花齊放的各種物件,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以外),輸出結果沒問題。但是對於引用型別,輸出結果只會是objectfunction,這並非我們預期的結果。

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判斷。


參考:

判斷JS資料型別的4種方法

JavaScript 資料型別和資料結構


歡迎關注我的微信公眾號:

前端基礎(一):js資料型別

相關文章