typeof
typeof
操作符返回一个表示数据类型的字符串,它可以应付常规场景下的数据类型判断。对基本数据类型 undefined
, boolean
, string
, number
和引用数据类型 function
都可以正确判断,但是对 null,数组,对象则统一返回 “object”。也就是说,typeof
不适合用来判断引用数据类型。
var a = 1
typeof a // "number"
var b = [1,2,3]
typeof b // "object"
var c = {}
typeof c // "object"
instanceof
instanceof
解决了上述问题,它的原理就是判断右操作数(通常是构造函数)的原型对象是否出现在左操作数(通常是实例)的原型链上,如果在则返回 true
。据此可以判断引用数据类型具体是哪种类型。
var b = [1,2,3]
b instanceof Array // true
var c = {}
c instanceof Object // true
需要注意的是,instanceof
对于不是通过 new 创建的基本数据类型无法做出正确的判断:
var a = 1
a instanceof Number // false
这是因为此时的 a 仅仅是一个基本类型的值,而不是实例对象,如果我们通过 new 创建 a,那么就能正确判断
var a = new Number(1);
a instanceof Number // true
结合 instanceof
的原理其实就很好理解其中原因了。
>>
另外要注意,instanceof
这个方法并非百试百灵 —— 假定脚本中有多个全局环境,例如 html 中有多个子 iframe,那么对于每一个全局环境而言,它都有自己版本的构造函数,进而有自己版本的原型链。instanceof
左右两边的操作数来自于不同全局环境时,即使实例和构造函数对应,也只会返回 false。
Object.getPrototypeOf()
let arr = [1,2];
console.log(Object.getPrototypeOf(arr) === Array.prototype); // true
利用原型链。存在同上问题。
isPrototypeOf()
let arr = [1,2];
console.log(Array.prototype.isPrototypeOf(arr)); // true
利用原型链。存在同上问题。
Object.prototype.toString.call()
let arr = [1,2];
`Object.prototype.toString.call(arr)`; //"[object Array]"
这个方法基本很完善,原理就是:在任何值上调用 Object 原生的 toString() 方法,都会返回一个格式为 [object NativeconstructorName] 的字符串。据此可以准确判断任何值的数据类型。
这里注意几个点:
arr 作为对象,也是 Object 的一个实例,为什么不直接使用
arr.toString()
?这是因为它的这个方法被重写了,即Array.prototype.toString()
。在使用arr.toString()
的时候,它优先在原型链上找到并调用了重写的方法,最后输出的是"1,2"
。对象字面量调用
toString()
的时候则依然输出"[object Object]"
,这是因为它没有重写这个方法,所以找到的是Object.prototype
的该方法。同样的,函数对象的
toString()
方法也被重写了,即Function.prototype.toString()
。调用的时候返回一个表示当前函数源代码的字符串。当对内置函数对象调用该方法时,返回如下格式的字符串:
Object.toString();
// "function Object() {
// [native code]
// }"
Array.toString();
// "function Array() {
// [native code]
// }"
实际上,这里的 Object 是构造函数,既然是函数,就可以看作是 Function 构造函数实例化的对象,因此这里相当于函数对象调用了 toString()
方法,也就是调用的 Function.prototype.toString()
方法。