分析四种数据类型检测

108 阅读2分钟

分析四种数据类型检测

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]” */