分析四种数据类型检测
typeof
局限性:
typeof null -> "object"
typeof 检测对象类型值,除了可执行对象{函数}可以检测出来是“function”,其余都是“object”
基于typeof检测一个未被声明的变量,结果是“undefined”,而不会报错「基于let在后面声明则会报错」
typeof 检测原始值对应的对象类型的值,结果是“object”
为啥: typeof检测数据类型是,按照计算机底层存储的二进制值,来进行检测的,它认为以“000”开始的都是对象,而null全是零
好处:简单、性能好
instanceof
临时用来“拉壮丁”检测数据类型,本意是检测当前实例是否属于这个类
* [value] instanceof [Ctor] => true/false
/*
@1 调用xxx instanceof yyy就会调用 yyy[Symbol.hasInstance](xxx)
@2 如果yyy是函数就用es6添加静态方法 因为yyy[Symbol.hasInstance] 找的是函数静态属性嘛
class yyy(){
static [Symbol.hasInstance] = function (){}
}
@3 如果yyy是实例就用原型那一套
class MyClass {
[Symbol.hasInstance](foo) {}
}
*/
好处:细分对象数据类型值「但是不能因为结果是TRUE,就说他是标准普通对象」
* 弊端:不能检测原始值类型的值「但是原始值对应的对象格式实例则可以检测」;但是因为原型链指向是可以肆意改动的,所以最后检测的结果不一定准确;
* 原理:按照原型链检测的;只要当前检测的构造函数(它的原型对象),出现在实例的原型链上,则检测结果就是TRUE;如果找到Object.prototype都没有找到,则结果是FALSE;
* f instanceof Fn -> Fn[Symbol.hasInstance](f)
* Function.prototype[Symbol.hasInstance]=function...
/*-----*/
class fn{
static [Symbol.hasInstance] = function (f){
console.log(1)
}
}
let f = new fn();
console.log(f instanceof fn) //=>相当于 fn[Symbol.hasInstance](f)
/*---不准确---*/
class fn{
static [Symbol.hasInstance] = function (f){
if(Array.isArray(f)) return true
return false
}
}
let f = new fn();
console.log([] instanceof fn)
constructor
constructor的修改比instanceof更“肆无忌惮”
Object.prototype.toString.call([value])
这是JS中唯一一个检测数据类型没有任何瑕疵的「最准确的,除了性能比typeof略微少那么一丢丢,写起来略微麻烦那么一丢丢」
"[object Number/String/Boolen/Null/Undefined/Symbol/BigInt/Object/Function/Array/RegExp/Date/Math/Error...]"
@1 Object.prototype.toString() 用来检测数据类型
@2 this指向谁就检测谁
1.为啥要用call?
([]).toString() 调用的是Array.prototype上的toString,是转换为字符串
* ({}).toString() 调用的是Object.prototype上的toString,是检测数据类型的「方法中的this是谁,就是检测谁的类型」 -> 我们需要把Object.prototype.toString执行,而且还要改变其中的this
* -> ({}).toString.call(10) =>“[object Number]”
2.检测返回值遵循啥规则?
一般都是返回当前实例所属的构造函数信息
* 但是如果实例对象拥有 Symbol.toStringTag 属性,属性值是啥,最后返回的就是啥,例如:Math[Symbol.toStringTag]="Math" => Object.prototype.toString.call(Math) “[object Math]”
console.log(Object.prototype.toString.call(1)) //=>Number
console.log(Object.prototype.toString.call(Number(1)))//=>Number
例题
function fn(){
fn.prototype[Symbol.toStringTag] = 'fn'
let f = new fn();
// f[Symbol.toStringTag] = 'f' //=>f
console.log(({}).toString.call(f)) //=>fn
/*------*/
class Fn {
constructor() {
this[Symbol.toStringTag] = 'Fn';
}
[Symbol.toStringTag] = 'Fn';
}
let f = new Fn;
console.log(Object.prototype.toString.call(Fn)); //“[object Function]”
console.log(Object.prototype.toString.call(f)); //“[object Fn]” */