为什么面试官要我写 instanceof

在前端面试中,instanceof 是一个常见的问题。面试官通常会要求面试者手写 instanceof 的实现,以测试他们对 JavaScript 类型系统和原型链的理解。


类型判断

在 JavaScript 中数据分为基本类型和引用类型。

  • 基本类型
    • Number
    • String
    • Boolean
    • undefined
    • null
    • Symbol
    • BigInt
  • 引用类型
    • Object
    • Array
    • Function
    • Date:日期对象
    • RegExp:正则表达式对象
    • MapSet
    • Promise
    • ...

在实际工作中,我们常常需要判断一个变量的类型。对于基本类型(null 除外) 和 Function 我们可以使用 typeof 进行判断。对于引用类型我们则需要使用 instanceof 进行判断。

js 复制代码
// 基本数据类型
let numberExample = 123;
let stringExample = "hello";
let booleanExample = true;
let nullExample = null;
let undefinedExample = undefined;
let symbolExample = Symbol("example");
let bigIntExample = BigInt(10);

// 引用类型
let objectExample = {};
let arrayExample = [];
let functionExample = function () {};
let dateExample = new Date();
let regExpExample = /abc/;
let mapExample = new Map();
let setExample = new Set();
let promiseExample = new Promise(() => {});

// typeof 适用范围
console.log(typeof numberExample); // number
console.log(typeof stringExample); // string
console.log(typeof booleanExample); // boolean
console.log(typeof undefinedExample); // undefined
console.log(typeof symbolExample); // symbol
console.log(typeof bigIntExample); // bigint
console.log(typeof functionExample); // function

// typeof 对 null 和于其他引用类型无法判断
console.log(typeof nullExample); // object。这是一个历史遗留问题,实际上 null 是基本数据类型
console.log(typeof objectExample); // object
console.log(typeof arrayExample); // object
console.log(typeof dateExample); // object
console.log(typeof regExpExample); // object
console.log(typeof mapExample); // object
console.log(typeof setExample); // object
console.log(typeof promiseExample); // object

// instanceof 判断对象具体是哪种类型的对象
console.log(objectExample instanceof Object); // true
console.log(arrayExample instanceof Array); // true
console.log(functionExample instanceof Function); // true
console.log(dateExample instanceof Date); // true
console.log(regExpExample instanceof RegExp); // true
console.log(mapExample instanceof Map); // true
console.log(setExample instanceof Set); // true
console.log(promiseExample instanceof Promise); // true

instanceof 是什么

MDN 定义: instanceof 是 JavaScript 的一个二元操作符,用于测试构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。换句话说,instanceof 可以用于判断一个对象是否由某个构造函数创建的。

js 复制代码
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}

const auto = new Car("Honda", "Accord", 1998);
console.log(auto instanceof Car); // true

在这个例子中,auto 是 Car 的一个实例,所以 auto instanceof Car 返回 true

注意:左侧可以是任意类型,而右侧必须是一个函数的实例。参数错误时会报错。


instanceof 原理

每个对象都有一个 __proto__ 属性。在对象创建的时候会将 __proto__ 属性指向它的构造函数的 prototype 属性上。并且构造函数的 prototype 属性本身也是一个对象。它也有自己的 __proto__ 属性。通过 __proto__ -> prototype 这样串联形成一个链条,这个链条就是原型链。原型链的终点是 ObjectObject.prototype.__proto__ 的值为 null

每个对象的构造函数都可以在原型链上找到,因此 instanceof 通过原型链可以判断对象是否由某个构造函数创建。


实现一个 instanceof

手写 instanceof

手写 instanceof 的实现可以帮助我们更深入地理解 JavaScript 的原型链。下面是一个简易的 instanceof 实现:

  1. 参数校验
  2. 比较 obj.__proto === constructor.prototype
    1. 找到就立即返回 true
    2. 遍历到原型链终点 constructor.prototype === null 时,返回 false
js 复制代码
function myInstanceof(obj, constructor) {
	const BASIC_TYPE = [
		"[object Undefined]",
		"[object Null]",
		"[object Number]",
		"[object String]",
		"[object Boolean]",
		"[object Symbol]",
		"[object BigInt]",
	];

	const objType = Object.prototype.toString.call(obj);
	const constructorType = Object.prototype.toString.call(constructor);

	if (BASIC_TYPE.includes(constructorType)) {
		throw TypeError("Right-hand side of 'instanceof' is not an object");
	}
	if (typeof constructor !== "function") {
		throw TypeError("Right-hand side of 'instanceof' is not callable");
	}
	if (BASIC_TYPE.includes(objType)) {
		return false;
	}

	let objProto = Reflect.getPrototypeOf(obj);
	while (objProto !== null) {
		if (Object.is(objProto, constructor.prototype)) {
			return true;
		}
		objProto = Reflect.getPrototypeOf(obj);
	}
	return false;
}

当传入的参数是对象时,如果操作成功 Reflect.getPrototypeOf(target) 返回对象的原型,如果操作失败(比如,目标不是对象)则返回 false

测试结果


总结

本文介绍了 JavaScript 类型判断的方法。对 instanceof 的概念、用法和实现进行了说明。

资料

相关推荐
浅水壁虎24 分钟前
vue基础(第二章 )
前端·javascript·vue.js
界面开发小八哥24 分钟前
界面控件DevExtreme v26.1新版亮点——支持Angular 22
前端·javascript·angular.js·devexpress·ui开发·devextreme
mONESY1 小时前
React useState 核心原理与最佳实践:从异步更新到性能优化全解
javascript
腻害兔2 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
gis开发之家3 小时前
《Vue3 从入门到大神37篇》Vue3 源码详解(七):watch 与 watchEffect 源码对比——副作用是如何被追踪的?
javascript·前端框架·vue3·vue3源码
bloglin999994 小时前
langchain 和 langgraph 和 react
javascript·react.js·langchain
触底反弹4 小时前
🚀 删了数据刷新又回来?3 组件 × 4 回调 × 3 坑讲透 React 父子通信
前端·javascript·react.js
会周易的程序员6 小时前
js-shm: 高性能 Node.js 共享内存模块
开发语言·javascript·c++·node.js·共享内存·shm
带娃的IT创业者6 小时前
重新定义前端构建速度:深度解析 SWC 如何用 Rust 颠覆 JavaScript 工具链
前端·javascript·rust·前端构建·swc
新中地GIS开发老师7 小时前
零基础WebGIS开发入门 | GeoJSON数据持久化
前端·javascript·gis·webgis·三维gis开发