instanceof
当我们判断一个数据为基本数据类型,比如String、Number、Boolean等,我们可以用typeof直接实现,但是如果是引用数据类型,这个typeof显得有点力不从心了,因为你看下面得例子
let reg = /\d{1,4}/
let obj = {}
let arr = []
console.log(typeof reg); // object
console.log(typeof obj); // object
console.log(typeof arr); // object
是不是你就没有办法用typeof实现了呢,javascript的语法规范在设计的时候已经考虑到这一点,给我们提供了一个instanceof完美解决了对象类型的判断。
instanceof 及其工作原理
首先,我们来看一下在mdn上是如何解释instanceof这个语法的解释:
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
语法
// object:某个instance、constructor:某个构造函数
object instanceof constructor
描述
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上
var simpleStr = "This is a simple string";
var myString = new String();
var newStr = new String("String created with constructor");
var myDate = new Date();
var myObj = {};
var myNonObj = Object.create(null);
simpleStr instanceof String; // 返回 false,非对象实例,因此返回 false
myString instanceof String; // 返回 true
newStr instanceof String; // 返回 true
myString instanceof Object; // 返回 true
myObj instanceof Object; // 返回 true,尽管原型没有定义
({}) instanceof Object; // 返回 true,同上
myNonObj instanceof Object; // 返回 false,一种创建非 Object 实例的对象的方法
myString instanceof Date; //返回 false
myDate instanceof Date; // 返回 true
myDate instanceof Object; // 返回 true
myDate instanceof String; // 返回 false
替代方案
Object.prototype.toString,我们可以利用这个方法来对一个变量的类型来进行比较准确的判断
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('hi') // "[object String]"
Object.prototype.toString.call({a:'hi'}) // "[object Object]"
Object.prototype.toString.call([1,'a']) // "[object Array]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(() => {}) // "[object Function]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"
实现原理
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);
// expected output: true
console.log(auto instanceof Object);
// expected output: true
当然,instanceof 也可以判断一个实例是否是其父类型或者祖先类型的实例
let person = function () {
}
let programmer = function () {
}
programmer.prototype = new person()
let nicole = new programmer()
nicole instanceof person // true
nicole instanceof programmer // true
这是 instanceof 的用法,但是 instanceof 的原理是什么呢?根据 ECMAScript 语言规范,我梳理了一下大概的思路,然后整理了一段代码如下
function new_instance_of(leftVaule, rightVaule) {
let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
while (true) {
if (leftVaule === null) {
return false;
}
if (leftVaule === rightProto) {
return true;
}
leftVaule = leftVaule.__proto__
}
}
其实 instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。
原型链小结
Function是javascript中的根对象,它不通过new操作符所创建,而是自己创建了自己构造函数才有原型对象constructor.prototype__prop__是所有实例对象都有原型属性- 所有的
构造函数是Function这个顶级构造函数的实例
有了以上几句总结,几乎就涵盖了原型链所有的关系,万变不离其宗。
以上文章,参考了浅谈 instanceof 和 typeof 的实现原理