做者: JowayYoung
倉庫: Github、 CodePen
博客: 掘金、 思否、 知乎、 簡書、 頭條、 CSDN
公衆號: IQ前端
聯繫我:關注公衆號後有個人 微信喲
特別聲明:原創不易,未經受權不得對此文章進行轉載或抄襲,不然按侵權處理,如需轉載或開通公衆號白名單可聯繫我,但願各位尊重原創的知識產權
本文由筆者師妹LazyCurry創做,收錄於筆者技術文章專欄下前端
JS的變量與其餘語言的變量有很大區別,由於其變量鬆散的本質,決定了變量只是在特定時間內用於保存特定值的一個名字而已,變量的值及其數據類型可在聲明週期內改變。git
JS的數據類型可分爲基本類型和引用類型,先簡單介紹兩種數據類型,再來分析判斷數據類型的幾種方法。固然,這個也是大廠常考的面試題,同窗們可按照文章的思路進行回答和擴展,讓面試官耳目一新。github
基本類型
基本類型包括Undefined、Null、String、Number、Boolean、Symbol
。基本類型按值訪問,因此咱們可操做保存在變量中實際的值。面試
基本類型的值在內存中佔據固定大小的空間,是被保存在棧內存中。從一個變量向另外一個變量複製基本類型的值,會建立這個值的一個副本,這兩個值徹底獨立地存放在棧內存中。segmentfault
引用類型
引用類型是對象類型,包括Object、Array、Function、Data、Regexp、Error
。引用類型的值是保存在堆內存中的對象,JS不容許直接訪問內存中的位置,也就是說不能直接訪問操做對象的內存空間。數組
操做對象時,其實是在操做對象的引用,因此說引用類型的值是按引用訪問的。從而有[1, 2] === [1, 2]
爲false
。微信
簡單的講完JS的兩種數據類型,接下來介紹一下JS判斷數據類型的4種方法。app
typeof
typeof是肯定一個變量是string
、number
、boolean
、symbol
(ES6新增類型)仍是undefined
的最佳工具。注意,這裏並無說起null
以及引用型數據。框架
typeof可能返回下面某個結果,結果的對應值以下:frontend
null
)typeof undefined; // undefined typeof null; // object typeof "這是一段字符串"; // string typeof 1; // number typeof true; // boolean typeof new Symbol(); // symbol typeof new Object(); // object typeof new Function(); // function typeof new Date(); // object
上面的例子中,對於基本類型來講,除開null
均可返回正確的結果。調用typeof null
會返回object
,是由於null被認爲是一個空的對象引用,所以返回了object,固然這個也是JS設計語言早期遺留的Bug。
而在其餘引用類型,除開function
均返回object
類型,所以用typeof來判斷引用類型數據的類型並不可取,typeof
適合用來判斷基礎類型值。
instanceof
instanceof
可用來判斷一個實例對象是否屬於一個構造函數,其表達式A instanceof B
,若是A是B的實例,則返回true
,不然返回false
。
實現原理其實就是在A的原型鏈上尋找是否有原型等於B.prototype,若是一直找到A原型鏈的頂端null,仍然找不到原型等於B.prototype,那麼就可返回false
。原型鏈的知識可戳往期文章《來自原形與原型鏈的拷問》回顧下哦,這裏就再也不講原型鏈啦~
new Date() instanceof Date; // true new Date() instanceof Object; // true [] instanceof Array; // true [] instanceof Object; // true function Person() {}; const person = new Person(); person instanceof Person; // true person instanceof Object; // true
從上面的例子可看到,instanceof
可判斷出[]
是Array
的實例,Date
對象是Date
的實例,person
是Person構造函數
的實例,到這裏並沒什麼問題,可是instanceof
認爲這些也都是Object
的實例,這就有點使人疑惑。
其實可根據instanceof
的實現原理來分析一下,上面已經講過實現原理,在這裏咱們套用一下instanceof
用於數組判斷的過程。
[] instanceof Array
,由於能找到[].__proto__
指向Array.prototype
,所以返回true。[] instanceof Object
,在這裏就是也是要沿着[]
的原型鏈找,有[].__proto__
指向Array.prototype
,又由於Array.prototype
默認是Object的實例,因此有Array.prototype.__proto__
指向了Object.prototype
,所以這就是爲何instanceof
認爲[]
也是Object
的實例。
instanceof
只能用來判斷兩個對象是否屬於實例關係,並不能判斷一個對象屬於什麼類型。簡單說,就是判斷兩個類是否從屬關係。
instanceof
的問題在於,假如只有一個全局執行環境,若是網頁中有兩個框架,實際上就存在兩個不用的全局執行環境,從而存在兩個不一樣版本的Array
構造函數。若是從一個框架向另外一個框架傳入一個數組,那麼傳入的數組與第二個框架中原生建立的數組分別是不一樣的構造函數。
const iframe = document.createElement("iframe"); document.body.appendChild(iframe); const IArray = window.frames[0].Array; const iarr = new IArray(); iarr instanceof Array; // false Array.isArray(iarr); // true
爲了解決這個問題,ES5新增了Array.isArray()
,這個方法能肯定某個值是否是數組或類數組。
constructor
上面提到的原型鏈,原型對象的constructor
屬性指向了構造函數,又由於實例對象的__proto__
屬性指向原型對象,所以可有:每個實例對象均可經過constructor來訪問它的構造函數
。而JS內置對象在內部構建時也是這麼作的,所以可用來判斷數據類型。
"".__proto__.constructor === String; // true // 下面將屬性__proto__去掉,效果相同 "".constructor === String; // true new Number(1).constructor === Number; // true true.constructor === Boolean; // true [].constructor === Array; // true new Date().constructor === Date; // true new Function().constructor === Function; // true
可看出,大部分類型都能經過這個屬性來判斷。可是因爲undefined
和null
是無效的對象,所以是沒有constructor
屬性的,這兩個值不能用這種方法判斷。另外,當重寫原型時,原型原有的constructor
會丟失,這時判斷也就不生效了。
function Person() {}; Person.prototype = { name: "XX" }; const person = new Person(); person.constructor === Person; // false
這時打印person.constructor
,可看到是一個Object。爲何會變成Object呢?這是由於在從新定義原型時,傳入的是一個對象{}
,{}
是new Object()
的字面量,所以會將Object原型上的constructor
傳遞給{}
,因此person.constructor
也就打印出了Object。
所以,在重寫原型對象時,都須要給constructor
從新賦值,來保證對象實例的類型不改變。這個點在開發時記得記得注意!
toString
Object.prototype.toString
方法返回對象的類型字符串,所以可用來判斷一個值的類型。由於實例對象有可能會自定義toString方法,會覆蓋Object.prototype.toString
,因此在使用時,最好加上call
。會有如下返回值:
[object Undefined]
:未定義的值[object Null]
:空值[object String]
:字符串[object Number]
:數值[object Boolean]
:布爾[object Symbol]
:惟一值[object Object]
:對象[object Array]
:數組[object Function]
:函數[object Date]
:日期[object RegExp]
:正則[object Error]
:錯誤Object.prototype.toString.call(undefined); // [object Undefined] Object.prototype.toString.call(null); // [object Null] Object.prototype.toString.call("這是字符串"); // [object String] Object.prototype.toString.call(1); // [object Number] Object.prototype.toString.call(true); // [object Boolean] Object.prototype.toString.call({}); // [object Object] Object.prototype.toString.call([]); // [object Array] Object.prototype.toString.call(new Function()); // [object Function] Object.prototype.toString.call(new Date()); // [object Date] Object.prototype.toString.call(new RegExp()); // [object RegExp] Object.prototype.toString.call(new Error()); // [object Error]
總結與對比
typeof
使用簡單,可是隻適用於判斷基礎類型數據instanceof
能判斷引用類型,不能檢測出基本類型,且不能跨iframe使用 constructor
基本能判斷全部類型,除了null和undefined,可是constructor容易被修改,也不能跨iframe使用toString
能判斷全部類型,所以可將其封裝成一個全能的DataType()
判斷全部數據類型function DataType(tgt, type) { const dataType = Object.prototype.toString.call(tgt).replace(/\[object (\w+)\]/, "$1").toLowerCase(); return type ? dataType === type : dataType; } DataType("young"); // "string" DataType(20190214); // "number" DataType(true); // "boolean" DataType([], "array"); // true DataType({}, "array"); // false
JS的四種判斷方法都有各自的優勢跟缺點,要根據具體狀況採起合適的判斷方式。那麼就到這裏啦,有什麼寫得不對還麻煩各位大佬指出。有大家的支持我還會繼續寫出更好的文章~
❤️關注+點贊+收藏+評論+轉發❤️,原創不易,鼓勵筆者創做更好的文章
關注公衆號IQ前端
,一個專一於CSS/JS開發技巧的前端公衆號,更多前端小乾貨等着你喔
關鍵詞
免費領取視頻教程我微信
拉你進技術交流羣IQ前端
,更多CSS/JS開發技巧只在公衆號推送