instanceof 你真的用对了吗?
在 JavaScript 中,instanceof 是一个常用的运算符,用于检测对象是否是某个构造函数的实例。然而,默认情况下它并不能直接用于判断基本数据类型(如 string、number、boolean 等)。
一、instanceof 的基本用法
instanceof 的语法如下:
object instanceof constructor
它用于检查 object 是否是 constructor 的实例。具体来说,它会检查 constructor.prototype 是否存在于 object 的原型链上。
示例:
function Person() {}
const p = new Person();
console.log(p instanceof Person); // true
console.log(p instanceof Object); // true
二、instanceof能不能用于判断基本数据类型?
首先我们需要了解instanceof 是怎么工作的?
obj instanceof Constructor
当执行上述代码时JavaScript 会做以下事情:
- 查看
Constructor[Symbol.hasInstance]是否存在。 - 如果存在,就调用这个方法,传入
obj。 - 如果没有,就按照原型链来判断(默认行为)。
所以若构造函数或类中没有重写Symbol.hasInstance,由于JavaScript 中的基本数据类型(如 number、string、boolean)不是对象,它们没有原型链。因此,使用 instanceof 判断基本类型会返回 false。例如:
console.log(123 instanceof Number); // false
console.log("hello" instanceof String); // false
console.log(true instanceof Boolean); // false
但在了解了instanceof 的工作机制后我们可以通过Symbol.hasInstance来自定义instanceof 操作符在某个类上的行为。
Symbol.hasInstance是一个内建符号,用于确定一个对象是否是某个构造函数的实例。- 默认情况下,
instanceof会检查原型链(即constructor.prototype是否存在于对象的原型链上)。 - 通过自定义
Symbol.hasInstance,可以改变instanceof的行为。
例如:
class Number {
static [Symbol.hasInstance](instance) {
return typeof instance === 'number';
}
}
console.log(1 instanceof Number) // true
上述代码的逻辑
-
定义一个类
Number这里定义了一个类,叫做
Number。目前这个类没有任何内容,只是个空类。class Number {} -
添加一个静态方法
[Symbol.hasInstance]。在这个方法中可以自定义instanceof的判断逻辑
static [Symbol.hasInstance](instance) { return typeof instance === 'number' }这是关键部分:
-
static表示这是一个静态方法(属于类本身,不属于实例)。必须是静态方法,因为 JavaScript 的
instanceof运算符只会在构造函数上查找Symbol.hasInstance,而不是在实例或原型上。 -
[Symbol.hasInstance]是一个动态属性名,表示这个方法的名字是Symbol.hasInstance。 -
(instance)是参数,表示被判断的对象。
所以这行代码的意思是:给
Number类添加一个静态方法,这个方法会在使用instanceof时被调用。 -
其他重写Symbol.hasInstance方式
-
直接给类赋值
class Number {} Number[Symbol.hasInstance] = function(instance) { return typeof instance === 'number'; }; -
普通函数来构造类
function Number() {} Number[Symbol.hasInstance] = function(instance) { return typeof instance === 'number'; };
三、手动实现一个 instanceof
要手动实现一个类似于 instanceof 的功能,我们需要检查构造函数的 prototype 是否存在于对象的原型链中。
实现思路:
- 获取对象的原型;
- 获取构造函数的原型对象;
- 从对象的原型开始,沿着原型链向上查找;
- 如果找到构造函数的原型对象,返回
true; - 如果查找到原型链顶端(
null)仍未找到,返回false。
手写实现:
function myInstanceOf(obj, constructor) {
// 获取构造函数的 prototype
const prototype = constructor.prototype;
// 获取对象的原型
let currentProto = Object.getPrototypeOf(obj);
// 沿着原型链查找
while (currentProto !== null) {
if (currentProto === prototype) {
return true;
}
currentProto = Object.getPrototypeOf(currentProto);
}
return false;
}
测试:
function Person() {}
const p = new Person();
console.log(myInstanceOf(p, Person)); // true
console.log(myInstanceOf(p, Object)); // true
console.log(myInstanceOf(p, Array)); // false
console.log(myInstanceOf(123, Number)); // false
console.log(myInstanceOf(new Number(123), Number)); // true
可以看到,基本类型 123 不是 Number 的实例,而 new Number(123) 是。