JavaScript 类型检测
JavaScript有四种类型检测(typeof
,instanceof
,constructor
,Object.prototype.toString.call()
),它们都有自己的特点。平时使用时我么要注意一些坑。
如果是感觉只想学习一个完善的类型检测的方法的同学,建议直接Object.prototype.toString.call()
。
文章目录
数组检测 isArray()
这个比较特殊,因为面试可能会问数组的检测方法,我们理应学一下。
描述
Array.isArray() 用于确定传递的值是否是一个 Array
。
语法
Array.isArray(obj)
使用例
Array.isArray([1, 2, 3]);
// true
Array.isArray({foo: 123});
// false
Array.isArray("foobar");
// false
Array.isArray(undefined);
// false
内部实现
因为IE8不支持此方法,如果有面试官问你怎么实现,就用下面方式顶回去。
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
typeof
描述
**typeof
**操作符返回一个字符串,表示未经计算的操作数的类型。
语法
typeof num
typeof (num)
注意,typeof
并不是JavaScript
内置函数、对象,而是一个运算符。
使用例
console.log(typeof undefined) // "undefined"
console.log(typeof null)//"object"
console.log(typeof [])//"object"
console.log(typeof "")//"string"
console.log(typeof 1)//"number"
console.log(typeof (_=>{}))//"function"
console.log(typeof Symbol)//"function"
console.log(typeof Symbol())//"Symbol"
class MyClass{}
console.log(typeof new MyClass())//"object"
我们能直观看到typeof
的不足之处!比如,我们无法检测数组类型、无法检测自定义的类。所以我们在项目中应当慎用typeof
。
instanceof
描述
**instanceof
**运算符用于测试构造函数的prototype
属性是否出现在对象的原型链中的任何位置。
语法
console.log(Array instanceof Object)//true
instanceof
是一个二元运算符,两边必须是对象,如A instanceof B
将会在B
的原型链中检查是否存在A
,如果存在返回true
,否则返回false
。
注意:1 instanceof Number
是错误的语法,因为1并不是对象。
使用例
console.log([1,2,3] instanceof Array)//true
console.log(new Number(0) instanceof Number)//true
console.log(new Number(0) instanceof Object)//true
console.log((_=>{}) instanceof Function)//true
class A{}
class B extends A{}
let a = new A()
let b = new B()
console.log(a instanceof B)//false
console.log(b instanceof A)//true
通过上面代码,我们也能发现一些问题,我们的Number
可以匹配Number
,同时也可以匹配Object
。我们知道原理,因为所有对象原型链的终点都是Object
。
所以,我们在使用instanceof
检测类型时,应当避免在选择结构开头放上num instanceof Object
这样的语句。
constructor
描述
返回创建实例对象的 Object
构造函数的引用。*注意,此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。*所有对象都会从它的原型上继承一个 constructor
属性。
语法
obj.prototype.constructor;
obj.constructor;
使用例
var o = {};
o.constructor === Object; // true
var o = new Object;
o.constructor === Object; // true
var a = [];
a.constructor === Array; // true
var a = new Array;
a.constructor === Array // true
var n = new Number(3);
n.constructor === Number; // true
class A {}
class B extends A { }
let a: A = new A();
let b: B = new B();
console.log(a.constructor === A)//true
console.log(b.constructor === B)//true
console.log(b.constructor === A)//false
是的,我们貌似可以用constructor
来检测类型了,但是有没有缺点和漏洞呢?您好,有的!举个例子:
function MyArray(){}
MyArray.prototype = new Array()
let myarr = new MyArray()
console.log(myarr.constructor === MyArray)//false
console.log(myarr.constructor === Array)//true
在我们使用不完善的继承、或者修改了prototype
而不修改constructor
属性,就会造成上面的错误,我们无法匹配我们想要的类型。
但是,只要我们小心的使用constructor
属性,还是能给我们带来不少便利。
Object.prototype.toString.call()
描述
toString()
方法返回一个表示该对象的字符串。
每个对象都有一个 toString()
方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()
方法被每个 Object
对象继承。如果此方法在自定义对象中未被覆盖,toString()
返回 “[object type]”,其中 type
是对象的类型。
语法
Object.prototype.toString()
使用例
let f = Object.prototype.toString;
console.log(f.call("123")) // [object String]
console.log(f.call(null)) // [object Null]
console.log(f.call(undefined)) // [object Undefined]
console.log(f.call(/aaaa/)) // [object RegExp]
class A{}
let a = new A()
function MyArray(){}
MyArray.prototype = new Array()
let myarr = new MyArray()
console.log(f.call(a)) // [object Object]
console.log(f.call(myarr))// [object Object]
缺点还是有点明显,toString
只能检测出内置类型,无法检测出自定义类,所以我们应当在项目中,混用Object.prototype.toString
与instanceof
。