Object.prototype.toString.call()作为安全的类型检测方法,为什么没有满大街地被使用
我们知道,基本的类型检测用typeof,引用类型检测用instanceof,还有专门用于检查是不是数组的Array.isArray()。
let b = false; typeof b; //返回"boolean"
let n = 10; typeof n; //返回"number"
let s = "hello"; typeof s; //返回"string"
let u = undefined;typeof u; //返回"undefined"
let nul = null; typeof nul;//返回"object"
let arr = [];
let reg = /[a-z]/;
let obj = {}
let fun = function(){}
arr instanceof Array; //返回true
reg instanceof RegExp; //返回true
obj instanceof Object; //返回true
fun instanceof Function;//返回true
Array.isArray(arr); //返回true
Array.isArray(obj); //返回false
现在来看看,如果使用Object.prototype.toString.call()会是一个什么样的情况。
let b = false;
let n = 10;
let s = "hello";
let u = undefined;
let nul = null;
let arr = [];
let reg = /[a-z]/;
let obj = {}
let fun = function(){}
Object.prototype.toString.call(b)//返回"[object Boolean]"
Object.prototype.toString.call(n)//返回"[object Number]"
Object.prototype.toString.call(s)//返回"[object String]"
Object.prototype.toString.call(u)//返回"[object Undefined]"
Object.prototype.toString.call(nul)//返回"[object Null]"
Object.prototype.toString.call(arr)//返回"[object Array]"
Object.prototype.toString.call(reg)//返回"[object RegExp]"
Object.prototype.toString.call(obj)//返回"[object Object]"
Object.prototype.toString.call(fun)//返回"[object Function]"
我们稍作一下改进:
const _toString = value => Object.prototype.toString.call(value).slice(8,-1);
_toString(nul);//返回"Null"
_toString(b); //返回"Boolean"
_toString(n); //返回"Number"
_toString(arr);//返回"Array"
_toString(obj);//返回"Object"
从上面的例子可以看出,确实,相较于typeof、instanceof、Array.isArray,Object.prototype.toString.call更可靠,甚至null,它都检测出来了。但这个方法似乎并没有被满大街地使用。
webpack源码更青睐typeof,instanceof,和Array.isArray,比如截取的这段代码,用来解析module.rules中某个规则的test、include和exclude字段,这3个字段的值可以是字符串、函数、正则表达式和数组。
Vue源码做类型检测时,也很喜欢typeof,instanceof 和Array.isArray()。只是在做严格的类型检测时,会使用到Object.prototype.toString。
function isPrimitive(value){
return (
typeof value === "string" ||
typeof value === "number" ||
typeof value === "symbol" ||
typeof value === "boolean"
);
}
function isPromise(val){
return (
isDef(val) &&
typeof val.then === "function" &&
typeof val.catch === "function"
)
}
function isObject(obj){
return obj!==null && typeof obj === "object";
}
//作严格的类型检测时,会用到Object.prototype.toString
var _toString = Object.prototype.toString;
function toRawType(value){
return _toString.call(value).slice(8,-1);
}
function isPlainObject(obj){
return _toString.call(obj) === '[object Object]';
}
function isRegExp(v){
return _toString.call(v) === '[object RegExp]';
}
日常开发中,typeof,instanceof 和Array.isArray()能够满足所需,Object.prototype.toString.call更像是锦上添花,没有到非用不可的地步。况且,Object.prototype.toString.call有原生的限制,它拿非原生构造函数没啥办法。
class Point{
constructor(x,y){
this.x = x;
this.y = y;
}
toValue(){
return this.x+this.y;
}
}
let p = new Point(1,2);
Object.prototype.toString.call(p); //返回"[object Object]"
p instanceof Point; //返回true
更糟的是,Object.prototype.toString方法还可能被覆写。
做个小结吧,类型检测方法有 typeof | instanceof | Array.isArray | Object.prototype.toString.call,作为“安全”的类型检测方法Object.prototype.toString.call也可能不准确。
上一篇: 这个用两条腿走路的机器人未来会怎样