typeof
一般情况下:
- 用来判断值类型;
// 值类型
console.log(typeof '') // 'string'
console.log(typeof undefined) // 'undefined'
console.log(typeof true) // 'boolean'
console.log(typeof 1) // 'number'
- 用来判断是否为函数;
// 函数类型
function demo() {}
console.log(typeof demo); // 'function'
console.log(typeof Object); // 你new一个object就是一个函数 'function',object应该是个构造函数
- 用来判断是否为引用类型;
// 引用类型
console.log(typeof null); // object null显示为'object',是因为作者设计typeof语法的历史遗留问题,并不是期望此处引用一个对象的说法;
console.log(typeof {}); // object
console.log(typeof []); // object
来看看这个表达式有哪些局限性。
局限性一:使用new形式创造的变量,会判断为’object ’ 。
console.log(typeof new String(''));
解释:
new出来的基本类型使用构造函数创建的,不止有变量内容,还有附带的属性方法,实质是个对象,所以显示object;
局限性二:判断NaN是’number’。
console.log(typeof 3); // 'number'
console.log(typeof NaN); // 'number'
一般我们写代码声明变量也不会用new去创造,所以typeof还是很适用的。
instanceof
判断xxx是否是该类型的实例,结果为布尔值(本质是看变量的__proto__
属性是否指向某个构造函数的prototype
属性)。用法:
console.log(xxx instanceof 类型)
// 以下为true
console.log(new String('123') instanceof String)
console.log(new Number(1) instanceof Number)
console.log(function(){} instanceof Object) // 因为顶层原型就是Object
console.log({} instanceof Object)
console.log([] instanceof Array)
console.log([] instanceof Object) // 因为顶层原型就是Object
其实类似:
console.log(obj.__proto__.constructor === 类型)
var str = new String('123')
console.log(str.__proto__.constructor === String) // true
对于类来说也可以判断:
// 以下都为true
xiaoming instanceof Student
xiaoming instanceof People // 条件:Student继承至People
xiaoming instanceof Object // 因为顶层原型就是Object
局限性一:不用new声明的基本类型,都显示false。
console.log('1' instanceof String) // false
console.log(1 instanceof Number) // false
console.log(true instanceof Boolean) // false
个人理解是因为instanceof语法并没有触发基本类型的包装对象;
局限性二:undefined、null、NaN这三个没有可实例化的构造函数,直接报错。
var obj = null
console.log(obj instanceof null) // 报错
var obj = undefined
console.log(obj instanceof undefined) // 报错
console.log(NaN instanceof NaN) // 这个也是报错的
不过还是可以用来判断是不是自己写的类
function Person(name, age) {
this.name = name;
this.age = age;
}
var person = new Person("小明", 12);
console.log(person instanceof Person) // true
constructor
哎,这个我也不喜欢用,不过可以用来判断数组(一般第三方库里用来做辅助判断)。判断xxx的构造函数是谁,用法:
console.log(xxx.constructor === Array)
// 判断为String
console.log(''.constructor)
console.log(new String('').constructor)
// 判断为Array
console.log([].constructor)
console.log(new Array().constructor)
// 判断为Number
let num = 1
console.log(num.constructor) // 注意:直接 1.constructor 会报错
console.log(new Number(1).constructor)
// 判断为Object
console.log({}.constructor)
// 判断为Boolean
console.log(true.constructor)
// 判断为Function
function demo() {}
console.log(demo.constructor)
局限性一:undefined、null、NaN没有构造函数,直接报错。
局限性二:使用不安全,因为contructor的指向是可以改变的。
Object.prototype.toString.call()
这个几乎无敌,就是太长了。意思是使用call方法,改变最外层Object的this指向,指向()内的变量,让最外层Object的toString方法为()内变量使用。
console.log(Object.prototype.toString.call(null)) // '[object Null]'
console.log(Object.prototype.toString.call(undefined)) // '[object Undefined]'
console.log(Object.prototype.toString.call('')) // '[object String]'
console.log(Object.prototype.toString.call(1)) // '[object Number]'
console.log(Object.prototype.toString.call(true)) // '[object Boolean]'
console.log(Object.prototype.toString.call([]) ) // '[object Array]'
console.log(Object.prototype.toString.call({})) // '[object Object]'
console.log(Object.prototype.toString.call(fn)) //'[object Function]'
还可以判断Date类型和正则表达式
var date = new Date();
console.log(Object.prototype.toString.call(date)) //'[object Date]'
var reg = /[^\d]/g;
console.log(Object.prototype.toString.call(reg)) //'[object RegExp]'
虽然这么牛逼,但是还是有局限性的
局限性一:NaN还是判断为Number 。
console.log(Object.prototype.toString.call(NaN)) // '[object Number]'
局限性二:对于自己写的类new出来的对象,只会判断为’[object Object]’ 。
function Person(name, age) {
this.name = name;
this.age = age;
}
var person = new Person("小明", 12);
console.log(Object.prototype.toString.call(person));
// '[object Object]' 不是 '[object Person]'
isNaN()
为了解决一些运算过程中产出NaN的值,比如Number()转换,Math方法的一些运算错误等,isNaN()判断变量是否为NaN,用法。
console.log(isNaN(123)) // false
console.log(isNaN(NaN)) // true
局限性:因为()内如果不是纯数字类型,那么底层会先执行Number(),进而导致判断错误。
console.log(isNaN('a')) // true
// 实际上先执行了Number('a'),拿到结果再看看是否为NaN
// 例子:
console.log(isNaN({})) // true
console.log(isNaN(['a'])) // true
console.log(isNaN([])) // false
console.log(isNaN([123])) // false
console.log(isNaN(['123'])) // false
个人感觉靠谱一些的方法是
方法一:
function checkNaN(value) {
return typeof value === 'number' && isNaN(value);
}
方法二:利用NaN自己不等于自己的特性,NaN === NaN 为false
function checkNaN(value) {
return value !== value
}
后面ES6出了个
Object.is ()
方法解决了NaN === NaN 为false的问题,可以理解为更加严格的===
console.log(Object.is(NaN, NaN)); // true
方法三:ES6的Number.isNaN()
Number.isNaN([123]) // false
这个方法是底层先判断是不是一个number类型,然后再看看值是不是NaN,是就返回true。
拓展:
let arr = [NaN]
arr.indexOf(NaN) // -1 找不到子项
arr.includes(NaN) // true
是因为两个方法实现的底层机制不一样。
val = !val
这个好哇,可以用来判断某个变量是否为undefined或者null
let val = null
console.log(val = !val) // 为true
// 以下是自己看的小例子,可以忽略哈
const symbolFormat = (data, val, styb) => {
val = !val ? '%' : val;
if (isNaN(data)) return;
return parseFloat(data).toFixed(styb || 2) != 0 ? val : '';
}
Array.isArray()
用这个方法可以判断是不是数组:
Array.isArray(arr) // 返回布尔值
这个方法的缺点是当伪数组(例如函数的arguments参数,DOM集合)使用伪数组.__proto__ = Array.prototype
后,伪数组的判断就为真了。
总结
如果不想记上面这么多,可以参考我的个人判断习惯:
- 一般情况下都可以用
typeof
; - 数组用
Array.isArray()
方便; - NaN最好用自己封的函数;
- 同时判断
null
和undefined
用val = !val
求求给个赞吧,会有不定时更新补充…