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()