总所周知JavaScript在一般情况下可以利用typeof
来判断一个数据的类型,除了一些特殊情况,比如typeof null
会输出object
。这里要说的是另一种情况,用typeof
判断数组也会输出object
。
首先创建一个数组
let arr = [1,2,3]
//或 let arr = new Array([1,2,3])
1.instanceof
console.log(arr instanceof Array) // true
2.Array.isArray()
console.log(Array.isArray(arr)) // true
3.Object.prototype.toString.call()
(这个才是重点)
根据MDN的描述,每个数据类型对象都会有一个toString()
方法,默认情况下这个方法会被每个数据类型的对象从Object
对象的原型继承过来,而数组也是对象,自然也会继承这个方法,以下是各种类型调用这个函数后的输出:
ar 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()
后都会将值转换为字符串类型,而obj
调用的时候则会返回对象的类型,这个时候我们试一下对不同类型打印调用toString()
的结果:
console.log(Object.toString()) // function Object() { [native code] }
console.log(Array.toString()) // function Array() { [native code] }
console.log(Number.toString()) // function Number() { [native code] }
console.log(Boolean.toString()) // function Boolean() { [native code] }
console.log(Function.toString()) // function Function() { [native code] }
// ...其他类型同理
由此可见虽然每种数据类型的toString()
方法都是从Object
对象的原型继承而来,但同时也重写了这个方法,Object
对象原型上的toString()
方法是可以输出数据类型的,因此如果想要准确判断数据类型,就可以直接使用原型上的toString()
。
使用call()
方法将想要判断数据类型的对象作为参数(原理大概就是改变了Object
的this指向)
console.log(Object.prototype.toString.call(arr)) // [object Array]
成功判断。
PS:如果想要验证一下,可以把Array
中的toString()
删掉,像这样
// 定义一个数组
var arr = [1, 2, 3]
// 数组原型上是否具有 toString() 方法
console.log(Array.prototype.hasOwnProperty('toString')) //true
// 数组直接使用自身的 toString() 方法
console.log(arr.toString()) // '1,2,3'
console.log(arr.toString() === Object.prototype.toString.call(arr)) //false
// delete操作符删除数组原型上的 toString()
delete Array.prototype.toString
// 删除后,数组原型上是否还具有 toString() 方法
console.log(Array.prototype.hasOwnProperty('toString')) //false
// 删除后的数组再次使用 toString() 时,会向上层访问这个方法,即 Object 的 toString()
console.log(arr.toString()) // '[object Array]'
console.log(arr.toString() === Object.prototype.toString.call(arr)) //true
可以看到当我们删除数组类型自己的toString()
后,再次调用toString()
就会沿着原型链找到Object()
对象原型中的toString()
,这个时候就能用于判断类型了。