检测数据类型的方法
typeof 底层原理及优缺点
typeof
类型检测
- 检测原始值类型
typeof null; 'object'
typeof undefined;'undefined'
typeof 1/-1;'number'
typeof NaN;'number'
typeof Infinity;'number'
typeof true;'boolean'
typeof 'guyal';'string'
typeof ''; 'string'
typeof Symbol();'symbol'
typeof 10n;'bigint'
- 对象类型
typeof {} 'object'
typeof [] 'object'
typeof /^$/ 'object'
- 函数
typeof function(){}; 'function'
typeof 底层原理
- 计算机底层都是通过二进制来进行数据存储的,以不同的数字开头代表不同的数据类型,比如:
- 1:数字
- 010:浮点数
- 100:字符串
- 110:布尔
- 000:对象
- -2^30:undefined
- JS 设计上的缺陷
- 凡是以 000 开始的都认为是对象,null 是 000000,所以误认为 null 是 object 类型 「这是 JS 设计的缺陷」
typeof 特点
- typeof null 的结果是:'object'
- typeof 实现 call 的对象,比如:函数,箭头函数、生成器函数、构造函数..,其结果是:'function';其余未实现 call 的对象,结果是:'object'
- 检测出来的结果是字符串,字符串的内容就是数据对应的类型
- 检测原始值类型还是比较简单方便的
typeof 缺点
- 对于对象数据类型,检测出来的结果都是 'object',函数是'function'
- 因为 typeof 检测是基于构造函数创建出来的,基本数据类型的实例对象,也是一个对象:'object',所以使用 typeof 检测出来的对象类型是:object 类型
typeof null 的结果为什么是 object 类型
计算机底层都是根据二进制来存储数据的,以 000 开头的代表对象,而 null 是 000000,计算机误认为是对象,所以,typeof 的检测结果是'object'
instanceof 原理及优缺点
instanceof 用途
- 主业:检测某个实例是否属于某个类
- 副业:数据类型检测「可以细分出部分对象的类型」
instanceof 使用范围
- 基本类型值和 Symbol 类型不能使用「本身不是对象,没有__proto__ 属性」
- 但是,可以检测基于构造函数创建出来的基本类型对象值
instanceof 底层原理
- 内置原理:
- 通过类的 Symbol.hasInstance 属性来实现的
- Symbol.hasInstance:用于判断对象是否为构造器的实例
- 底层原理:
- 首先查找 Symbol.hasInstance,如果存在那么就会基于这个属性检测,如果不存在,则基于原型链 proto 查找,只要构造器的 prototype 出现在实例的原型链上,那么结果就为 true;
- 长话短说:检测当前构造函数的原型 prototype,是否出现在实例的原型链上,如果有,结果就是 true;
instanceof 存在的问题
- 只能基于 class 方式构建 Symbol.hasInstance
方法才会生效:
static [Symbol.hasInstance](实例) {
return Array.isArray(实例)
}
- 所有实例的原型链最终都会指向 Object.prototype,所以:实例 instanceof Object 的结果都为 true
- 在原生 JS 中,原型链都是可以随意改动的,所以,检测出来的结果是不准确的
- 字面量方式创建的基本数据类型值不能通过 instanceof 方法检测:浏览器不会默认把原始值转换为 new 的方式,所以本身不是对象,不存在__proto__ 属性
- 不能检测原始值类型
重写 instanceof
Symbol.hasInstance
Object.getPropertyOf
// 重写 instanceof 方法
function my_instanceOf(exam, ctor) {
let exam_ = typeof exam,
ctor_ = typeof ctor;
// 必须保证构造器是一个函数
if (ctor_ !== 'function' || !ctor.prototype) throw new TypeError(ctor+'is not an constructor')
// 排除 null、undefined
if(exam == null) return false;
// 排除原始值
if (!/^(object|function)$/i.test(exam_) ) return false;
// 条件都可满足
// 检测是否存在 [Symbol.hasInstance]()
if (typeof ctor[Symbol.hasInstance] === 'function'){
return ctor[Symbol.hasInstance](exam)
}
// 不存在 [Symbol.hasInstance](),基于原型链机制检测
let proto = Object.getPrototypeOf(exam);
while (proto) {
// 判断 proto 与 ctor.prototype 是否相等
if(proto === ctor.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}
console.log(my_instanceOf([], Array)); //->true
console.log(my_instanceOf([], RegExp)); //->false
console.log(my_instanceOf([], Object)); //->true
Object.prototype.toString.call( [value] )
检测范围
- Number.prototype
- String.prototype
- Symbol.prototype
- BigInt.prototype
- Array.prototype
- RegExp.prototype
- Function.prototype
返回值
- 大部分内置类的原型上都有 toString,一般都是转换为字符串,只有 Object.prototype 上的 toString 并不是转换为字符串,而是返回当前实例对象所属类的信息的:'[object 所属类的构造函数信息]'
内置原理
- 所属类的构造函数信息是根据 Symbol.toStringTag 获取的
- 有这个属性基于这个获取的,没有则是浏览器自己计算的
- toString() 找不到 toStringTag 属性时只好返回默认的 Object
Object.prototype.toString.call 是检测数据类型方式的万全之策
constructor
constructor 是可以肆意被修改的,所以也不准,这里就不多说了。
以上内容,如有错误之处,请给予指正!感谢~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!