为什么不能使用typeof去获取类型?
| 类型 | 结果 |
|---|---|
| Undefined | "undefined" |
| Null | "object"(原因) |
| Boolean | "boolean" |
| Number | "number" |
| BigInt | "bigint" |
| String | "string" |
| Symbol | "symbol" |
| Function(在 ECMA-262 中实现 [[Call]];classes也是函数) | "function" |
| 其他任何对象 | "object" |
可以看到使用typeof是有局限性的。null 会被判定为 “object” 其他任何对象(array date等)都会判定为“object”,这是不严谨的。 使用Object.prototype.toString()方法则能准确的获取到调用toString()方法的类型。
Object.prototype.toString的返回值
首先我们需要知道Object.prototype.toString是什么? 他就是Object原型对象上绑定的一个方法,所有基于Object创建的类型都能够顺着原型链向上找到toString方法.
Object.prototype.toString()
'[object Object]'
可以看到Object.prototype.toString()返回值是Object 这是因为Object.prototype本身是一个对象,记住他的核心:返回调用者的数据类型。
当我们需要判定其他数据类型时,需要使用call改变this的指向问题:
Object.prototype.toString.call([])
'[object Array]'
Object.prototype.toString.call({})
'[object Object]'
Object.prototype.toString.call(1)
'[object Number]'
Object.prototype.toString.call("1")
'[object String]'
Object.prototype.toString.call(function(){})
'[object Function]'
Object.prototype.toString.call(/d+/)
'[object RegExp]'
核心:返回调用者的数据类型。可以看到当我们改变了this(改变调用者),则能准确的拿到调用者的类型。
那为什么不能使用每种类型的toString()呢?
控制台打印{} 或者 [] 都能看到__poto__上绑定的toString方法,直接使用会怎样?
使用每种数据类型的各自的toString方法
let arr=[1,"2",[1,2],{1:2}]
arr.prototype.toString()
'1,2,1,2,[object Object]'
Number.prototype.toString.call({})
VM3674:1 Uncaught TypeError: Number.prototype.toString requires that 'this' be a Number
at Object.toString (<anonymous>)
at <anonymous>:1:27
String.prototype.toString.call([])
VM3701:1 Uncaught TypeError: String.prototype.toString requires that 'this' be a String
at Array.toString (<anonymous>)
at <anonymous>:1:27
可以看到,每种数据类型上的toString都和Object.prototype.toString表现不一样,数组则是将元素转换为字符串,内部对象转成[object Object],而Number传入{}直接报错. 由此可见,每种类型的toString都是被重新定义过的,只适用于当前类型
array.prototype.toString()相对特殊
Array.prototype.toString.call({}); <!--"[object Object]"-->
Array.prototype.toString.call(function(){}) <!--"[object Function]"-->
Array.prototype.toString.call(1) <!--"[object Number]"-->
Array.prototype.toString.call('1')<!--"[object String]"-->
表现基本和Object.prototype.toString相似,但是this指向null和undefined时表现不同:
Object.prototype.toString.call()
'[object Undefined]'
Object.prototype.toString.call(null)
'[object Null]'
Array.prototype.toString.call()
VM4071:1 Uncaught TypeError: Cannot convert undefined or null to object
at toString (<anonymous>)
at <anonymous>:1:26
(anonymous) @ VM4071:1
Array.prototype.toString.call(null)
VM4105:1 Uncaught TypeError: Cannot convert undefined or null to object
at toString (<anonymous>)
at <anonymous>:1:26
所以使用Object.prototype.toString更加准确一些
toString()
可以在控制台直接输入toSting看执行情况
toString(1)
'[object Undefined]'
toString({})
'[object Undefined]'
本质上就等于 Object.prototype.toString.call() 或 Object.prototype.toString.call(undefined)
你也可以使用toString.call()去代替使用Object.prototype.toString.call() 【不建议,可能window中会复写toString】
toString.call({})
'[object Object]'
toString.call([])
'[object Array]'
如果没有在window中复写toString 则直接调用toString方法或者使用window.toString方法就等于使用Object.prototype.toString
如果复写:
let toString=function(){console.log('1111')}
toString.call()
1111
toString.call(222)
1111
可以看到输出的是复写后的内容