再也不用擔心變數類型錯誤!學會JS中如何輕鬆檢查變數類型

来源:https://www.cnblogs.com/tanggoahead/archive/2023/06/13/17478991.html
-Advertisement-
Play Games

## 顏色 1. **RGB** (紅,綠,藍)三種顏色的集合,最低值是0(十六進位00)到最高值255(十六進位FF) 2. **HSL** H色相(0-360),S飽和度(百分比),L亮度(百分比) 3. (不)透明度 **rgba、hsla** (新版瀏覽器可不寫a,直接寫4個值) ## li ...


今天要分享的問題就是:如何在JS中檢查一個變數的類型?

先上結論:
如果判斷的是基本數據類型或JavaScript內置對象,使用toString;如果要判斷的是自定義類型,請使用instanceof。

在 ECMAScript 規範中,共定義了 7 種數據類型,分為 基本類型引用類型 兩大類。

基本類型 也稱為簡單類型,按值訪問。

引用類型 也稱為複雜類型,按址訪問。
JavaScript內置了一些引用類型,如圖所示:

JavaScript的變數是鬆散類型。雖然這使得提供類型信息的方式更加靈活了,但也容易誤用。

下麵來分析常見的四種JavaScript類型檢查方法:typeof, instanceof, constructor, toString

typeof

typeof是一個操作符,其右側跟一個一元表達式,並返回這個表達式的數據類型。

它返回的結果用該類型的字元串(全小寫字母)形式表示。返回值有7種取值:numberbooleansymbolstringundefinedobjectfunction

typeof 3; // number 有效
typeof true; //boolean 有效
typeof Symbol(); // symbol 有效
typeof ''; // string 有效
typeof undefined; //undefined 有效
typeof null; //object 無效
typeof [] ; //object 無效
typeof new Function(); // function 有效
typeof new Date(); //object 無效
typeof new RegExp(); //object 無效

有些時候,typeof操作符會返回一些令人迷惑但技術上卻正確的值:

  • 對於基本類型 ,除 null 以外,均可以返回正確的結果。
  • 對於引用類型 ,除 function 以外,一律返回object類型。
  • 對於null ,返回object類型。這是一個知名的bug。由於影響範圍越來越大,就沒有修複了。
  • 對於function 函數,返回 function 類型。從技術角度講,函數在ECMAScript中是對象,不是一種數據類型。然而,函數也確實有一些特殊的屬性,因此通過typeof操作符來區分函數和其他對象是有必要的。

由上可以得出:
typeof引用類型 操作的返回值不是我們想要的結果。

instanceof

instanceof是用來判斷 A 是否為 B 的實例的。它的表達式為:A instanceof B

如果 A 是 B 的實例,則返回 true,否則返回 false。 在這裡需要特別註意的是:instanceof斷規則是某個對象的原型鏈是否包含某個構造函數的prototype屬性

let arr = [];
arr instanceof Array; // true
arr instanceof Object; // true

看看arr原型鏈簡圖:

arr的 __proto__ 直接指向Array.prototype,間接指向 Object.prototype,所以按照 instanceof 的判斷規則,[] 就是Array的實例,也是Object的實例。instanceof返回值都是true

依此類推,RegExp, Object, Function也會形成一條對應的原型鏈 。

/abc/ instanceof RegExp // true
({}) instanceof Object // true
(function(){}) instanceof Function // true

instanceof是通過原型鏈來檢查類型的,所以適用於任何"object"的類型檢查。自定義的類型同樣滿足。

// 比如直接原型關係
function Fruit(){ }
(new Fruit) instanceof Fruit     // true

// 原型鏈上的間接原型
function Apple(){}
Apple.prototype = new Fruit
(new Apple) instanceof Fruit         // true

註意instanceof基本數據類型 不起作用,因為基本數據類型沒有原型鏈。

3 instanceof Number // false
true instanceof Boolean // false
'abc' instanceof String // false
null instanceof String  // always false
undefined instanceof String  // always false

但你可以這樣:

new Number(3) instanceof Number // true
new Boolean(true) instanceof Boolean // true
new String('abc') instanceof String // true

但這時你已經知道數據類型了,類型檢查已經沒有意義了。

使用constructor屬性

constructor 屬性返回一個指向創建了該對象原型的函數引用。需要註意的是,該屬性的值是那個函數本身。例如:

function Fruit(){}
var a = new Fruit
a.constructor === Fruit    // true

constructor不適合用來判斷變數類型。

  • 其一,它是一個屬性,非常容易被偽造:
var a = new Fruit
a.constructor === Array
a.constructor === Fruit    // false
  • 其二,constructor指向的是最初創建當前對象的函數,是原型鏈最上層的那個方法:
function Apple(){}
Apple.prototype = new Fruit

function BadApple(){}
BadApple.prototype = new Apple

(new BadApple).constructor === Fruit   // true
Fruit.constructor === Function       // true

與instanceof類似,constructor只能用於檢測引用對象,對基本數據類型無能為力。

與instanceof不同的是,在訪問基本數據類型的屬性時,JavaScript會自動調用其構造函數來生成一個對象。例如:

(3).constructor === Number // true
true.constructor === Boolean // true
'abc'.constructor === String // true
// 相當於
(new Number(3)).constructor === Number
(new Boolean(true)).constructor === Boolean
(new String('abc')).constructor === String

這種將一個值類型轉換為對象引用類型的機制在其他語言中也存在,稱為裝箱

但在基本數據類型中,nullundefined調用constructor會拋出TypeError異常。

null.constructor         // TypeError!
undefined.constructor    // TypeError!

因為null是JavaScript原型鏈的起點,undefined是無效對象,都沒有構造函數,也就不存在constructor屬性。

instanceof跨視窗問題

我們知道Javascript是運行在宿主環境下的,而每個宿主環境會提供一套ECMA標準的內置對象,以及宿主對象(如window, document),一個新的視窗即是一個新的宿主環境。 不同視窗下的內置對象是不同的實例,擁有不同的記憶體地址。

instanceofconstructor都是通過比較兩個Function是否相等來進行類型判斷的。 此時顯然會出問題,例如:

var iframe = document.createElement('iframe');
var iWindow = iframe.contentWindow;
document.body.appendChild(iframe);

iWindow.Array === Array         // false
// 相當於
iWindow.Array === window.Array  // false

因此iWindow中的數組arr原型鏈上是沒有window.Array的。請看:

iWindow.document.write('<script> var arr = [1, 2]</script>');
iWindow.arr instanceof Array            // false
iWindow.arr instanceof iWindow.Array    // true

使用toString方法

使用toString方法是最為可靠的類型檢測手段,它會將當前對象類型轉換為字元串並輸出。

toString屬性定義在Object.prototype上,因而所有對象都擁有toString方法。但Array, Date等對象會重寫從Object.prototype繼承來的toString,所以最好用Object.prototype.toString來檢測類型。

toString = Object.prototype.toString;

toString.call(new Date);  // [object Date]
toString.call(new String);// [object String]
toString.call(Math);      // [object Math]
toString.call(3);         // [object Number]
toString.call([]);        // [object Array]
toString.call({});        // [object Object]

// Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null);      // [object Null]

採用toString也不是完美的,它無法檢測用戶自定義類型。因為Object.prototype是不知道用戶會創造什麼類型的,它只能檢測ECMA標準中的那些內置類型。

toString.call(new Fruit) // [object Object]

因為返回值是字元串,也避免了跨視窗問題。當然IE彈窗中還是有Bug,不必管它了。 現在多少人還在用IE?多少人還在用彈窗?

和Object.prototype.toString類似地,Function.prototype.toString也有類似功能,不過它的this只能是Function,其他類型(例如基本數據類型)都會拋出異常。

其他

有時Duck Typing的類型推斷方式也非常可行,貌似已經成為了前端的慣例。比如jQuery是這樣判斷一個Window的:

isWindow: function(obj){
    return obj && typeof obj === 'object' && "setInterval" in obj;
}

總結

  • typeof只能檢測基本數據類型,對於null還有Bug;
  • instanceof適用於檢測對象,它是基於原型鏈運作的;
  • constructor指向的是最初創建者,而且容易偽造,不適合做類型判斷;
  • toString適用於ECMA內置JavaScript類型(包括基本數據類型和內置對象)的判斷;
  • 引用類型 檢查都有跨視窗問題,比如instanceof和constructor。

總之,如果你要判斷的是基本數據類型或JavaScript內置對象,使用toString; 如果要判斷的是自定義類型,請使用instanceof。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 企業數字化轉型以數據為中心,通過數據驅動業務發展、管理協同和運營。因此,數字化轉型關鍵在於數據,數據治理則需先行。從而更好激發數據生產要素潛能,實現業務數據化、數據價值化,助力企業數字化轉型。 ## 那麼何為數據治理? 國際數據管理協會(DAMA)在其《DAMA數據管理知識體系指南(第2版)》一書中 ...
  • # 資料庫模式設計如果不好會導致的問題: 1.冗餘 2.導致數據一致性出現問題 3.插入異常 4.更新異常 5.刪除異常 # 函數依賴 函數依賴是指一個或多個屬性的取值可以確定另一個屬性的取值。具體地說,如果一個關係模式R中屬性集合X的取值能唯一地確定屬性集合Y的取值,那麼我們稱屬性集合Y對於屬性集 ...
  • 這種只含map的操作,如果文件大小控制在合適的情況下,都將只有本地操作,其執行非常高效,運行效率完全不輸於在計算引擎Tez和Spark上運行。 ...
  • 摘要:併發的事務在運行過程中會出現一些可能引發一致性問題的現象,本篇將詳細分析一下。 本文分享自華為雲社區《MySQL讀取的記錄和我想象的不一致——事物隔離級別和MVCC》,作者:磚業洋__。 事務的特性簡介 1.1 原子性(Atomicity) 要麼全做,要麼全不做,一系列操作都是不可分割的,如果 ...
  • 之前寫過一篇文章“SQL Server如何找出視圖依賴的對象和視圖嵌套層數”,這裡我介紹一下Oracle資料庫中如何找出視圖的依賴對象以及視圖嵌套層數關係。主要通過DBA_DEPENDENCIES這個系統視圖(這個系統視圖中包含有對象的依賴關係數據)。另外,我們使用了Oracle的樹形查詢(層級查詢 ...
  • > ViewModel做為架構組件的三元老之一,是實現MVVM的有力武器。 ### ViewModel的設計目標 ViewModel的基本功能就是管理UI的數據。其實,從職責上來說,這又是對Activity和Fragment的一次功能拆分。以前存儲在它們內部的數據,需要它們自己處理創建,更新,存儲, ...
  • 隨著業務的發展及版本迭代,客戶端工程中不斷增加新的業務邏輯、引入新的資源,隨之而來的問題就是安裝包體積變大,前期各個業務模塊通過無用資源刪減、大圖壓縮或轉上雲、AB實驗業務邏輯下線或其他手段在降低包體積上取得了一定的成果。 ...
  • 本期直播《“元”來如此,“服務”直達——揭秘鴻蒙新流量陣地》聚焦**元服務**的**商業流量價值**,介紹元服務提供的服務直達和卡片動態變化等**輕量化服務**。網約停車旗艦平臺小強停車做客直播間,分享小強停車在HarmonyOS生態中,如何通過元服務為廣大用戶帶來更加便捷易用的線上預約停車體驗。快 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...