js 在if中,"", 0, NaN, false,null,undefined都爲false
根源:
true ==1 ;//true, false == 0;//true, true == "1";//true, false == "0";//true, false == "";//true, null == undefined;//true
某些情況我們需要對數據做嚴格的判斷,比如判斷每個變量或參數是不是undefined肯定不能直接if(a)去判斷,因爲a 如果爲“ ‘’ ”, 0, NaN, false,null,undefined”中的任意一個就都會進入if內從而導致bug。本篇博文詳細介紹判斷這些特殊數據類型的正確姿勢。
常規判斷
var a = "",b= null,c = undefined,d={},e=[];
var f;
check = k=> {
console.log(k+"的數據類型:" +typeof(k));
if(k){
console.log(k+"滿足條件進入判斷!")
}else{
console.log(k+"不滿足條件沒有進入判斷!")
}
}
k=> {
console.log(k+"的數據類型:" +typeof(k));
if(k){
console.log(k+"滿足條件進入判斷!")
}else{
console.log(k+"不滿足條件沒有進入判斷!")
}
}
check(a)
VM194:6 的數據類型:string
VM194:10 不滿足條件沒有進入判斷!
undefined
check(b)
VM194:6 null的數據類型:object
VM194:10 null不滿足條件沒有進入判斷!
undefined
check(c)
VM194:6 undefined的數據類型:undefined
VM194:10 undefined不滿足條件沒有進入判斷!
undefined
check(d)
VM194:6 [object Object]的數據類型:object
VM194:8 [object Object]滿足條件進入判斷!
undefined
check(e)
VM194:6 的數據類型:object
VM194:8 滿足條件進入判斷!
我們發現如果直接用變量進入if中判斷除了
var d={},e=[]; var f;
被if語句認爲是真外其餘都認爲是假。這樣就會帶來問題,假如我們要判斷某個變量就是undefined或者字符串空,或者null 就會出現問題。
如何判空 “”
這個問題最簡單,需要注意的是我們要判斷是否爲空就要考慮是判斷字符串的空還是對象的空,兩者是有區別的;
判斷字符串空:
var checkStrEmpety = str=>{
var reg = /^\s*$/;
if(typeof(str) === "string" && str === ""){
console.log("我是嚴格空字符串!")
}
}
上面方法判斷空字符串還缺少一步,如果字符串中有空格怎麼辦?
顯然含有空格的的字符串並未複合我們預期,所以還要改:
var checkStrEmpety = str=>{
var reg = /^\s*$/;
if(typeof(str) === "string" && str === "" || reg.test(str)){
console.log("我是嚴格空字符串!")
}
}
這樣我們就做到對嚴格空字符串的的判斷
var checkStrEmpety = str=>{
var reg = /^\s*$/;
if(typeof(str) === "string" && str === "" || reg.test(str)){
console.log("我是嚴格空字符串!")
}
}
undefined
checkStrEmpety("")
VM1068:4 我是嚴格空字符串!
undefined
checkStrEmpety(" ")
VM1068:4 我是嚴格空字符串!
undefined
checkStrEmpety(null)
undefined
判斷空對象
1.將json對象轉化爲json字符串,再判斷該字符串是否爲"{}"
var data = {};
var b = (JSON.stringify(data) == "{}");
alert(b);//true
如果打括號內有空格呢?
2.for in 循環判斷
var obj = {};
var b = function() {
for(var key in obj) {
return false;
}
return true;
}
alert(b());//true
3.jquery的isEmptyObject方法
此方法是jquery將2方法(for in)進行封裝,使用時需要依賴jquery
var data = {};
var b = $.isEmptyObject(data);
alert(b);//true
4.Object.getOwnPropertyNames()方法
此方法是使用Object對象的getOwnPropertyNames方法,獲取到對象中的屬性名,存到一個數組中,返回數組對象,我們可以通過判斷數組的length來判斷此對象是否爲空
注意:此方法不兼容ie8,其餘瀏覽器沒有測試
var data = {};
var arr = Object.getOwnPropertyNames(data);
alert(arr.length == 0);//true
5.使用ES6的Object.keys()方法
與4方法類似,是ES6的新方法, 返回值也是對象中屬性名組成的數組
var data = {};
var arr = Object.keys(data);
alert(arr.length == 0);//true
如何判斷0
var exp = 0;
if (typeof(exp) == "number" && !exp)
{
alert("0");
}
判斷 NaN
isNaN()
var tmp = 0/0;
if(isNaN(tmp)){
alert("NaN");
}
如何判斷null
checkNull = m=>{
if(typeof(m) == "object" && m==null){
console.log("null")
}
}
或者 ===
如何判斷false
checkNull = m=>{
if(typeof(m) == "boolean" && m==false){
console.log("null")
}
}
或者 ===
如何判斷數組
1.用instanceof判斷
typeof無法用於判斷數組是否爲數組,那麼用instance運算符來判斷。
instanceof運算符可以用來判斷某個構造函數的prototype屬性所指向的對象是否存在於另外一個要檢測對象的原型鏈上。在使用的時候語法如下:
object instanceof constructor
用我的理解來說,就是要判斷一個Object是不是數組(這裏不是口誤,在JavaScript當中,數組實際上也是一種對象),如果這個Object的原型鏈上能夠找到Array構造函數的話,那麼這個Object應該及就是一個數組,如果這個Object的原型鏈上只能找到Object構造函數的話,那麼它就不是一個數組。
const a = [];
const b = {};
console.log(a instanceof Array);//true
console.log(a instanceof Object);//true,在數組的原型鏈上也能找到Object構造函數
console.log(b instanceof Array);//false
由上面的幾行代碼可以看出,使用instanceof運算符可以分辨數組和對象,可以判斷數組是數組。
2.用constructor判斷
實例化的數組擁有一個constructor屬性,這個屬性指向生成這個數組的方法。
const a = [];
console.log(a.constructor);//function Array(){ [native code] }
以上的代碼說明,數組是有一個叫Array的函數實例化的。
如果被判斷的對象是其他的數據類型的話,結果如下:
const o = {};
console.log(o.constructor);//function Object(){ [native code] }
const r = /^[0-9]$/;
console.log(r.constructor);//function RegExp() { [native code] }
const n = null;
console.log(n.constructor);//報錯
看到這裏,你可能會覺得這也是一種靠譜的判斷數組的方法,我們可以用以下的方式來判斷:
const a = [];
console.log(a.constructor == Array);//true
但是,很遺憾的通知你,constructor屬性是可以改寫的,如果你一不小心作死改了constructor屬性的話,那麼使用這種方法就無法判斷出數組的真是身份了,不推薦啊
3.用Object的toString方法判斷
另一個行之有效的方法就是使用Object.prototype.toString方法來判斷,每一個繼承自Object的對象都擁有toString的方法。
如果一個對象的toString方法沒有被重寫過的話,那麼toString方法將會返回"[object type]",其中的type代表的是對象的類型,根據type的值,我們就可以判斷這個疑似數組的對象到底是不是數組了。
const a = ['Hello','Howard'];
const b = {0:'Hello',1:'Howard'};
const c = 'Hello Howard';
a.toString();//"Hello,Howard"
b.toString();//"[object Object]"
c.toString();//"Hello,Howard"
從上面的代碼可以看出,除了對象之外,其他的數據類型的toString返回的都是內容的字符創,只有對象的toString方法會返回對象的類型。所以要判斷除了對象之外的數據的數據類型,我們需要“借用”對象的toString方法,所以我們需要使用call或者apply方法來改變toString方法的執行上下文。
const a = ['Hello','Howard'];
const b = {0:'Hello',1:'Howard'};
const c = 'Hello Howard';
Object.prototype.toString.call(a);//"[object Array]"
Object.prototype.toString.call(b);//"[object Object]"
Object.prototype.toString.call(c);//"[object String]"
使用apply方法也能達到同樣的效果:
const a = ['Hello','Howard'];
const b = {0:'Hello',1:'Howard'};
const c = 'Hello Howard';
Object.prototype.toString.apply(a);//"[object Array]"
Object.prototype.toString.apply(b);//"[object Object]"
Object.prototype.toString.apply(c);//"[object String]"
我們就可以用寫一個方法來判斷數組是否爲數組:
const isArray = (something)=>{
return Object.prototype.toString.call(something) === '[object Array]';
}
cosnt a = [];
const b = {};
isArray(a);//true
isArray(b);//false
但是,此方法會污染原始數據類型的原型鏈,不推薦啊。
4.用Array對象的isArray方法判斷
爲什麼把這種方法放在最後講呢?因爲它是我目前遇到過的最靠譜的判斷數組的方法了,當參數爲數組的時候,isArray方法返回true,當參數不爲數組的時候,isArray方法返回false。
const a = [];
const b = {};
Array.isArray(a);//true
Array.isArray(b);//false
我試着在調用這個方法之前重寫了Object.prototype.toString方法:
Object.prototype.toString = ()=>{
console.log(‘Hello Howard’);
}
const a = [];
Array.isArray(a);//true
並不影響判斷的結果。
我又試着修改了constructor對象:
const a = [];
const b = {};
a.constructor = b.constructor;
Array.isArray(a);//true
OK,還是不影響判斷的結果。
可見,它與instance運算符判斷的方法以及Object.prototype.toString法並不相同,一些列的修改並沒有影響到判斷的結果。
你可以放心大膽的使用Array.isArray去判斷一個對象是不是數組。
除非你不小心重寫了Array.isArray方法本身。。
綜上最合適的判斷方法就是instanceof 和Array.isArray()