原理
console.log(Object.prototype.toString.call({})); //[object Object]
console.log(Object.prototype.toString.call([])); //[object Array]
console.log(Object.prototype.toString.call("")); //[object String]
console.log(Object.prototype.toString.call(123)); //[object Number]
实际上Object.prototype.toString.call()能够精准判断数据类型,是通过调用Object原型对象上的toString()方法,然后通过call()方法改变this的指向,将需要进行类型判断的数据(的上下文this)作为Object.prototype.toString()方法的执行环境。
那么这个时候就有一个疑问了,为什么Object原型对象的toString方法内部是怎么来拿到数据类型的呢?然后返回这样一个结果。
这时候不得不提起这个属性了 Symbol.toStringTag
,有兴趣的可以去MDN上查看这个属性。Object.prototype.toString()方法返回值[object Object]
中第二个Object就是Symbol.toStringTag
属性的返回值。至于为什么这么说,可看文章最后一节内容。
它的返回值是什么
那这个方法的返回值是数组吗?其实还是字符串,正如它的方法名toString()的中文意思一样,还是返回的字符串,只是形式看起来像数组。
console.log(Object.prototype.toString.call([])==="[object Array]"); //true
一定能精准判断数据类型吗
答案:不一定。
对象可以通过定义 Symbol.toStringTag 属性来更改 Object.prototype.toString() 的行为,从而导致意想不到的结果。
const myDate = new Date();
Object.prototype.toString.call(myDate); // [object Date]
myDate[Symbol.toStringTag] = "myDate";
Object.prototype.toString.call(myDate); // [object myDate]
Date.prototype[Symbol.toStringTag] = "prototype polluted";
Object.prototype.toString.call(new Date()); // [object prototype polluted]
所以说,假如你修改了Symbol.toStringTag 属性的值,那么通过Object.prototype.toString.call()方法返回的结果可能是其它类型。