js万能类型检测Object.prototype.toString.call——定制Object.prototype.toString.call的检测结果

时间:2023-02-13 07:53:38

javascript的类型检测

1、typeof

typeof操作符可以检测js的基础数据类型,包括number、string、boolean、undefined。因为null在二进制存储的值与object相同,所以typeof检测null会返回object。此为特例

2、instanceof

instanceof操作符可以检测某个对象是否属于某个构造函数,比如

var a = {}
a instanceof Object
// => true

他的原理是,检测对象的原型链中是否存在该构造函数的原型,所以上面的例子,我们可以更改他的结果

var a = {}
a.__proto__ = Boolean.prototype
a instanceof Boolean
// => true

其他

js中检测类型的方式有很多很多,除了以上两种之外,还可以通过constructor函数,或者Array.isArray, isNaN等等方式去判断类型这里不详细记述了

Object.prototype.toString.call

下面我们来介绍一下,今天要分享的主角,登登登~,诶就是Object.prototype.toString.call!
Object.prototype.toString.call可以说是javascript万能的类型检测方式了
请看栗子:

var obj = {}
Object.prototype.toString.call(obj)
// => '[object Object]'

var arr = []
Object.prototype.toString.call(obj)
// => '[object Array]'

var str = ''
Object.prototype.toString.call(str)
// => '[object String]'

var num = 23
Object.prototype.toString.call(num)
// => '[object Number]'

var bol = true
Object.prototype.toString.call(bol)
// => '[object Boolean]'

var nul = null
Object.prototype.toString.call(nul)
// => '[object Null]'

var udf = undefined
Object.prototype.toString.call(udf)
// => '[object Undefined]'

var date = new Date()
Object.prototype.toString.call(date)
// => '[object Date]'

var fn = () => {}
Object.prototype.toString.call(fn)
// => '[object Function]'

var map = new Map()
Object.prototype.toString.call(map)
// => '[object Map]'

var set = new Set()
Object.prototype.toString.call(set)
// => '[object Set]'

var regexp = new RegExp()
var regexp1 = /123/g
Object.prototype.toString.call(regexp)
Object.prototype.toString.call(regexp1)
// => '[object RegExp]'

Object.prototype.toString.call(window)
// => '[object Window]'

…大概有这么多,基本覆盖了所有能想到的类型
而且,这种检测方式相对来说又比较安全稳定,不容易被修改。除非你去覆盖Object.prototype.toSring方法。更改了Object.prototype.toSring方法还用Object.prototype.toSring去检测类型,这有点开玩笑的意思了。

既然这样,如果我定义了一个class

class Test {
	toString(){
		return 'test'
	}
}

const test = new Test()
Object.prototype.toString.call(test)
// => '[object Object]'

我们可以看到,即使我们重新定义了toString方法,并返回一个值,当使用
Object.prototype.toString.call(test)时,还是返回了’[object Object]',那我们该如何定制返回的类型呢?

es6规范

要想了解这个问题,我们必须要去了解es6的规范,其中规范规定了Object.prototype.toString.call的行为,它实际上是返回了被检测对象的Symbol.toStringTag的属性的值,该属性属于语言内部属性,无法被开发者直接访问,也无法在其属性中,原型链中被观测到。但是我们却可以更改这个属性的值。因此,我们也就可以定制Object.prototype.toSring的返回类型了

举例子

var arr = []
arr[Symbol.toStringTag] = '不知名前端'
Object.prototype.toString.call(arr)
// => '[object 不知名前端]'

class Test {
	constructor() {
        this[Symbol.toStringTag] = '不知名前端'
    }
}

const test = new Test()
Object.prototype.toString.call(test)
// => '[object 不知名前端]'

总结

要说这个知识有什么用,在什么场景可以用,可以说基本上是用不上。但是可以了解我们这些常用的方法,到底是什么原理,为什么会有这样的结果。在日常中遇到问题的时候,更能得心应手的排查问题。甚至优化自己的代码