1. 程式人生 > >JavaScript資料型別判斷的四種方法

JavaScript資料型別判斷的四種方法

### 碼文不易啊,轉載請帶上本文連結呀,感謝感謝 https://www.cnblogs.com/echoyya/p/14416375.html 本文分享了JavaScript型別判斷的四種方法:`typeof`、`instanceof`、`Object.prototype.toString.call()`、`constructor` [toc] **JavaScript資料型別** JavaScript有八種內建型別,除物件外,其他統稱為`基本型別` - 空值(null) - 未定義(undefined) - 布林值(boolean) - 數字(number) - 字串(string) - 物件 (object) - 符號(symbol, ES6中新增) - 大整數(BigInt, ES2020 引入) > Symbol: 是ES6中引入的一種原始資料型別,表示獨一無二的值。 > > BigInt:是 ES2020 引入的一種新的資料型別,用來解決 JavaScript中數字只能到 53 個二進位制位(JavaScript 所有數字都儲存成 64 位浮點數,大於這個範圍的整數,無法精確表示的問題。具體可檢視:新資料型別 — BigInt ### 一、typeof typeof是一個`操作符`而不是函式,其右側跟一個一元表示式,並返回這個表示式的資料型別。返回的結果用該型別的字串(全小寫字母)形式表示 包括以下 8 種:**string、number、boolean、undefined、function 、symbol、bigInt、object。** 對於陣列,物件,null以及時間等資料,typeof只能返回object,而不能直接返回對應的型別,還需要通過其他法判斷。 ``` console.log(typeof ""); // string console.log(typeof 1 ); // number console.log(typeof NaN ); // number console.log(typeof true); // boolean console.log(typeof undefined); // undefined console.log(typeof function(){}); // function console.log(typeof isNaN); // function console.log(typeof Symbol()); // symbol console.log(typeof 123n); // bigint console.log(typeof []); // object console.log(typeof {}); // object console.log(typeof null); // object console.log(typeof new Date()); // object console.log(typeof new RegExp()); // object ``` ### 二、instanceof instanceof 是用來判斷 `A 是否為 B 的例項`,表示式為:`A instanceof B`,如果 A 是 B 的例項,則返回 true,否則返回 false。 需特別注意:`instanceof 檢測的是原型` 即instanceof 用來比較一個物件是否為某一個建構函式的例項。**instanceof可以準確的判斷複雜資料型別,但是不能正確判斷基本資料型別** ``` console.log(12 instanceof Number); // false console.log('22' instanceof String); // false console.log(true instanceof Boolean); // false console.log(null instanceof Object); // false console.log(undefined instanceof Object); // false console.log(function a() {} instanceof Function); // true console.log([] instanceof Array); // true console.log({a: 1} instanceof Object); // true console.log(new Date() instanceof Date); // true ``` ### 三、constructor 1. JavaScript中,每個物件都有一個constructor屬性,可以得知某個例項物件,到底是哪一個建構函式產生的, constructor屬性表示原型物件與建構函式之間的關聯關係。 - 當一個函式F被定義時,JS引擎會為F新增prototype原型,然後在prototype上新增一個constructor屬性,並讓其指向F的引用,F利用原型物件的constructor屬性引用了自身,當F作為建構函式建立物件時,原型上的constructor屬性被遺傳到了新建立的物件上,從原型鏈角度講,建構函式F就是新物件的型別。這樣做的意義是,讓物件誕生以後,就具有可追溯的資料型別。 - 通過typeof運算子來判斷它是原始的值還是物件。如果是物件,就可以使用constructor屬性來判斷其型別。 - 如判斷陣列的函式: ``` function isArray(data){ return typeof data == "object" && data.constructor == Array; } isArray([]) // true ``` > 注意:null 和 undefined 是沒有 constructor 存在的,這兩種型別的資料需要通過其他方式來判斷。 ``` console.log('22'.constructor === String) // true console.log(true.constructor === Boolean) // true console.log([].constructor === Array) // true console.log(document.constructor === HTMLDocument) // true console.log(window.constructor === Window) // true console.log(new Number(22).constructor === Number) // true console.log(new Function().constructor === Function) // true console.log(new Date().constructor === Date) // true console.log(new RegExp().constructor === RegExp) // true console.log(new Error().constructor === Error) // true ``` 2. 如果修改了原型物件,一般會同時修改constructor屬性,防止引用的時候出錯。所以,修改原型物件時,一般要同時修改constructor屬性的指向。 ``` function Rectangle(width, height){ this.width = width; this.height = height; this.getArea = function(){ return '矩形的面積為' + (width * height); } } var rect1 = new Rectangle(40, 20); var rect2 = new Rectangle(50, 20); var rect3 = new Rectangle(60, 20); console.log(rect1.getArea()); console.log(rect2.getArea()); console.log(rect3.getArea()); ``` - **如上程式碼,每次例項化出一個物件,都會新增getArea方法,是三個物件共有且不變的,因此將getArea放在建構函式中就會在建立物件時被多次新增,浪費記憶體!** - **因此我們將getArea新增到原型物件上就減少了多次新增**,**例項化物件會沿著原型鏈查詢到此屬性** - **實現了共享屬性:** ``` function Rectangle(width, height){ this.width = width; this.height = height; } // 直接替換原型物件,但是要記得新增上建構函式屬性 Rectangle.prototype = { constructor: Rectangle, getArea: function(){ return '矩形的面積為' + (this.width * this.height); } } // 修改特性 Object.defineProperties(Rectangle.prototype, { constructor: { enumerable: false, configurable: false, writable: false }, getArea: { enumerable: false, configurable: false, writable: false } }) var rect1 = new Rectangle(40, 20); var rect2 = new Rectangle(50, 20); var rect3 = new Rectangle(60, 20); console.log(rect1.getArea()); console.log(rect2.getArea()); console.log(rect3.getArea()); ``` 3. 很多情況下,我們可以使用instanceof運算子或物件的constructor屬性來檢測物件是否為陣列。如很多JS框架就是使用這兩種方法來判斷物件是否為陣列型別。 但是檢測在跨框架(cross-frame)頁面中的陣列時,會失敗。原因就是在不同框架(iframe)中建立的陣列不會相互共享其prototype屬性。例如: ``` ``` ### 四、Object.prototype.toString.call() - `Object.prototype.toString(o)`是 Object 的原型方法, 1. 獲取物件o的class屬性。這是一個內部屬性, 2. 連線字串:[object + 結果(1)],格式為 [object Xxx] ,其中 Xxx 就是物件的型別。 - 對於 Object 物件,直接呼叫 toString() 就能返回 [object Object] 。而對於其他物件,則需要通過 call / apply 來呼叫才能返回正確的型別資訊。 ``` console.log(Object.prototype.toString.call(1)) // [object Number] console.log(Object.prototype.toString.call(1n)) // [object BigInt] console.log(Object.prototype.toString.call('123')) // [object String] console.log(Object.prototype.toString.call(true)) // [object Boolean] console.log(Object.prototype.toString.call(undefined)) // [object Undefined] console.log(Object.prototype.toString.call(null)) // [object Null] console.log(Object.prototype.toString.call({})) // [object Object] console.log(Object.prototype.toString.call([])) // [object Array] console.log(Object.prototype.toString.call(function a() {})) // [object Function] console.log(Object.prototype.toString.call(Symbol())) // [object Symbol] console.log(Object.prototype.toString.call(Math)) // [object Math] console.log(Object.prototype.toString.call(JSON)) // [object JSON] console.log(Object.prototype.toString.call(new Date())) // [object Date] console.log(Object.prototype.toString.call(new RegExp())) // [object RegExp] console.log(Object.prototype.toString.call(new Error)) // [object Error] console.log(Object.prototype.toString.call(window) // [object Window] console.log(Object.prototype.toString.call(document)) // [object HTMLDocument] ``` - 封裝一個準確判斷資料型別的函式 ```` function __getType(object){ return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; }; ```` - 可以解決上面的跨框架問題。 ```