前言
instanceof 和 Object.prototype.toString.call() 都是 JavaScript 中用来判断数据类型的方法,但它们使用的原理和实现方式有所不同。
一、instanceof
instanceof 运算符用于检测某个对象是否是某个构造函数的实例,其原理是通过查找原型链来确定实例与构造函数之间的关系。当一个对象的原型链上存在指定的构造函数时,instanceof 返回 true,否则返回 false。
具体实现可以通过遍历实例对象的原型链,一直沿着 proto 往上查找,判断是否等于构造函数的 prototype 属性,直到找到全局对象 Object 的 prototype 对象,如果还没有找到,则返回 false。
let obj = {}
let arr = [1, 2]
let num= 123
let str = 'hello'
//instanceof 判断obj是否是Object这种类型
console.log(obj instanceof Object);
// 输出:true obj.__proto__ === Object.prototype 实例对象的隐式原型等于构造函数的显式原型
console.log(arr instanceof Array);
// 输出:true arr.__proto__ === Array.prototype 实例对象的隐式原型等于构造函数的显式原型
console.log(arr instanceof Object);
// 输出:true arr.__proto__.__proto__ === Object.prototype 构造函数的显式原型还是一个对象,它还具有隐式原型
console.log(num instanceof Number);
// 输出:false instanceof 只能用于判断引用类型,不能用于判断原始类型。
console.log(str instanceof String);
// 输出:false instanceof 只能用于判断引用类型,不能用于判断原始类型。
二、Object.prototype.toString.call()
Object.prototype.toString.call() 是一个通用的方法,可以用来获取任何值的内部 [[Class]] 属性,它的返回结果是一个字符串,格式为 "[object Xxx]",其中 Xxx 表示数据类型。这个方法的本质是读取内置属性[[Class]]的值,而这个值就是一个字符串,表示数据的类型。
Object.prototype.toString.call() 方法的作用是检测数据类型,其参数必须是一个对象,如果参数是基本类型的值,会隐式转换成对应的包装对象。返回的结果是一个字符串,包含了数据类型信息。
例如,Object.prototype.toString.call([]) 返回的结果是 "[object Array]",而 Object.prototype.toString.call('hello') 返回的结果是 "[object String]"。
console.log(Object.prototype.toString.call("hello")); // 输出: "[object String]"
console.log(Object.prototype.toString.call(123)); // 输出: "[object Number]"
console.log(Object.prototype.toString.call(true)); // 输出: "[object Boolean]"
三、注意事项
- instanceof 只能用于判断引用类型,不能用于判断原始类型!!!
- Object.prototype.toString.call() 可以判断任何类型的数据,包括基本类型和引用类型。
- instanceof 的判断是基于原型链的查找,一旦原型链被修改,就有可能出现判断错误的情况。
- Object.prototype.toString.call() 的返回值中包含了数据类型信息,但只有一部分数据类型是符合预期的,例如对于 NaN 和 null,Object.prototype.toString.call() 返回的结果并不符合预期。
- Object.prototype.toString.call() 方法虽然可以检测数据类型,但也存在一些局限性,例如无法判断自定义对象的类型。
下面给出一些示例代码:
// instanceof 示例
function Person(name, age) {
this.name = name;
this.age = age;
}
const person = new Person('张三', 18);
console.log(person instanceof Person); // true
// Object.prototype.toString.call() 示例
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call('hello')); // [object String]
console.log(Object.prototype.toString.call(123)); // [object Number]
console.log(Object.prototype.toString.call(true)); // [object Boolean]
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(Symbol())); // [object Symbol]
//Object.prototype.toString.call()无法判断自定义对象的类型。
console.log(Object.prototype.toString.call({})); // [object Object]
console.log(Object.prototype.toString.call(function(){})); // [object Function]
console.log(Object.prototype.toString.call(new Date())); // [object Date]
console.log(Object.prototype.toString.call(Math)); // [object Math]
console.log(Object.prototype.toString.call(JSON)); // [object JSON]
这是因为在JavaScript中,一些内置对象(如函数、日期、数学等)拥有自己的特定类型,在调用Object.prototype.toString方法时会返回对应的类型标识。
{}是一个普通的对象,因此返回[object Object];function(){}是一个函数对象,因此返回[object Function];new Date()是一个日期对象,因此返回[object Date];Math是一个数学对象,因此返回[object Math];JSON是一个 JSON 对象,因此返回[object JSON]。
这些类型标识可以帮助我们确定对象的具体类型,与普通的对象类型 [object Object] 进行区分。