typeof
typeof 操作符返回 一个 字符串,表示未经计算的操作数的类型。(MDN)@H_ 502 _7@
typeof 可以用来检测 一个 值的类型。@H_ 502 _7@
1. 表现
在 ES6 之前,typeof 在浏览器的表现是这样的:@H_ 502 _7@
类型 结果 Boolean “boolean” String “string” Number “Number” Function “function” undefined “undefined” null “object” 数组 “object” 任意对象 “object”
typeof ; // 输出 :"number" typeof '嘎?' ; // 输出 :"string" typeof true ; // 输出 :"boolean" typeof undefined ; // 输出 :"undefined" var fn1 = function ( ) { } ; function fn2 ( ) { } ; typeof fn1 ; // 输出 :"function" typeof fn2 ; // 输出 :"function" typeof null ; // 输出 :"object" typeof [ ] ; // 输出 :"object"; typeof [ '9' , '9' , '6' ] ; // 输出 :"object"; typeof { } ; // 输出 :"object"
2. 为什么检查 null 的类型返回 object
这是 一个 历史遗留问题,JavaScript 从出现开始都是这个表现。@H_ 502 _7@
typeof null ; // 输出 :"object"
原因是 null 表示为 一个 空指针,其内部表示类型的 标签 和对象相同,所以会被设别为 object 。@H_ 502 _7@
有提案表示想要修复这个问题,使表现如下:@H_ 502 _7@
typeof null ; // 输出 :"null"
但这个提案被拒绝了。@H_ 502 _7@
3. 为什么检查数组类型返回 object
数组的本质是个对象,从数组的原型上观察就可以发现。@H_ 502 _7@
@H_ 502 _7@@H_ 502 _7@
同时可以通过 instanceof 检测数组的原型链上是否有 Object。@H_ 502 _7@
Array instanceof Object ; // 输出 :true
4. 由基础对象构建的值也返回 object
事实上 typeof 只对字面量敏感。@H_ 502 _7@
var num = ; typeof num ; // 输出 :"number"
如果采用构造 函数 的形式得到 一个 值:@H_ 502 _7@
var num = new Number ( ) ; typeof num ; // 输出 :"object"
所以除了 Function ,构造出来的 一个 值,使用 typeof 检测类型都会返回 object 。@H_ 502 _7@
var fn = new Function ( 'console.log("我是特例!")' ) ; typeof fn ; // 输出 :"function"
5. 更精准的检测类型
使用 Object.prototype.toString.call ,可以更精准的检测类型。@H_ 502 _7@
Object . prototype . toString . call ( ) ; // 输出 : [object Number] Object . prototype . toString . call ( false ) ; // 输出 : [object Boolean] Object . prototype . toString . call ( null ) ; // 输出 : [object Null] Object . prototype . toString . call ( [ ] ) ; // 输出 : [object Array] Object . prototype . toString . call ( { } ) ; // 输出 : [object Object]
通过观察结果可以看到,使用这个方式可以区别出数组、对象、null这些 typeof 无法区分的类型。@H_ 502 _7@
可是为什么要这样用呢?不能直接 调用 一个 值的 toString 吗?@H_ 502 _7@
这涉及到了原型的问题,例如 Number :@H_ 502 _7@
var number = ; console . log ( number . __proto__ . toString ) ;
number 变量的 toString 方法 其实就是 Number 的 prototype 属性 下的 toString 方法 。@H_ 502 _7@
var number = ; console . log ( number . __proto__ . toString === Number . prototype . toString ) ;
从这就可以看出进行 number.toString() 操作, 调用 的就不是 Object.prototype.toString 了。@H_ 502 _7@
这两个 toString 方法 的 内容 不同, Number.prototype.toString 做的事情其实就是根据一些规则,将值转成字符串,而 Object.prototype.toString 是将对象的 一个 类型 标签 进行组合 输出 。@H_ 502 _7@
也就是说大部分数据类型的原始对象都提供了新的 toString 方法 ,也就无法 调用 到 Object.prototype.toString ,所以要用这种方式。@H_ 502 _7@
那为什么 Object.prototype.toString 会可以精准判断出 一个 值的类型呢?@H_ 502 _7@
这是因为每个值都有 一个 对应的类型 标签 ,在标准中为 [[class]] 。@H_ 502 _7@
在 ES6 中,则是使用 Symbol.toStringTag 作为 标记 。@H_ 502 _7@
Object.prototype.toString 在 调用 的时候,就会访问这个 标记 ,并返回 [object 标记 ] 。@H_ 502 _7@
var obj = { [ Symbol . toStringTag ] : '996' , } ; Object . prototype . toString . call ( obj ) ; // 输出 :"[object 996]"
所有内置的类型都具有这个 标记 ,所以使用 Object.prototype.toString.call(值) 的方式可以更精准的 获取 到值的类型。@H_ 502 _7@
一些旧的数据类型的基础对象为了兼容性,可能访问不到 Symbol.toStringTag 接口,但是其他许多内置对象可以,例如 JSON 、 Math 、 BigInt 等:@H_ 502 _7@
JSON [ Symbol . toStringTag ] ; // 输出 :"JSON" Math [ Symbol . toStringTag ] ; // 输出 :"Math" BigInt . prototype [ Symbol . toStringTag ] ; // 输出 :"BigInt"
6. 小结
typeof 经常被用来检测基础类型,但是不够准确,无法区分数组、对象、null,更精准的检测应考虑使用 Object.prototype.toString 方法 。@H_ 502 _7@
delete 操作符 ? ?void声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did92438