Object.prototype.toString.call(obj) 可以用来检测传入参数的数据类型,最常见的就是用来检测数组。你是否有被问过怎样判断一个数据是否是数组类型?
这样的问题,如果你回答的是typeof
,那就得抓把紧多学学了。
这里我就不介绍所有可以判断数组类型的方法了,我只说Object.prototype.toString.call()
这一种方法,因为它让人觉得有点奇怪。
使用 Object.prototype.toString.call() 判断数组类型
使用方法很简单,举个例子:
var arr = [1, 2, 3]
console.log(Object.prototype.toString.call(arr)) // [object Array]
当我第一次知道可以这样判断数组类型时,我就觉得很奇怪,为什么要用这么奇怪的方法呢?当时的我并没有深究,只是记住了这个方法,但回过头来再仔细想想,这样的方法是有它的道理的。这段语法的意思是Object
这个对象的原型链上的toString()
方法执行在arr
这个上下文中,这里让人疑惑的就是为什么要用Object
上的toString()
方法,因为数组本身也有toString()
。要了解其原理,我们可能要先了解一下toString()
这个方法。
toString()
从字面上的意思就可以看出它可以将数据转换为字符串,但将各类型的数据转换为字符串的方式又不一样,如下:
var num = 123
num.toString() // '123'
var str = 'hello'
str.toString() // 'hello'
var bool = false
bool.toString() // 'false'
var arr = [1, 2, 3]
arr.toString() // '1,2,3'
var obj = {lang:'zh'}
obj.toString() // '[object Object]'
var fn = function(){}
fn.toString() // 'function(){}'
null.toString() // Cannot read property 'toString' of null
undefined.toString() // Cannot read property 'toString' of undefined
以上是各数据类型使用toString()
方法转换为字符串的结果,除了null
和undefined
不能转换以外,其他数据都有自己的方式变为字符串。
其实toString
是对象上的方法,每一个对象上都有这个方法,那就意味着数字
、字符串
和布尔值
这些基本数据类型不能使用toString()
方法,但上例中的基本数据类型却是可以使用,这要归功于javascript中的包装类,即Number
、String
和Boolean
。原始值不能有属性和方法,当要使用toString()
方法时,会先将原始值包装成对象再使用。
所以现在可以知道,上例中使用到的toString()
方法分别属于Number
、String
、Boolean
、Array
、Object
和Function
这些类。我们又知道在JavaScript中,所有类都继承自Object
,既然是继承,那么toString()
方法理应也被继承了,但看上例中的结果,显然toString()
并没有被继承,不然所有的输出结果应该都类似于'[object Object]'
这样。
其实各数据类型使用toString()
后的结果表现不一的原因在于:所有类在继承Object
的时候,改写了toString()
方法。原始Object
上的toString()
方法是可以输出数据类型的,如上例中的'[object Object]'
这个结果,所以当我们想要判断数据类型时,必须使用Object
上的toString()
方法。
验证
上面解释了为什么要使用Object
上的toString()
方法来判断数据类型,是因为其他类上的toString()
方法被改写了。为了加深理解,我们可以举个例子验证一下:
// 定义一个数组
var arr = [1, 2, 3]
// 数组原型上是否具有 toString() 方法
console.log(Array.prototype.hasOwnProperty('toString')) //true
// 数组直接使用自身的 toString() 方法
console.log(arr.toString()) // '1,2,3'
// delete操作符删除数组原型上的 toString()
delete Array.prototype.toString
// 删除后,数组原型上是否还具有 toString() 方法
console.log(Array.prototype.hasOwnProperty('toString')) //false
// 删除后的数组再次使用 toString() 时,会向上层访问这个方法,即 Object 的 toString()
console.log(arr.toString()) // '[object Array]'
当我们删除了Array
自己的toString()
方法后,再次使用时会向上查找这个方法,即Object
的toString()
,这是原型链的知识。
至此,总算整明白了Object.prototype.toString.call()
为什么要这么用。