JS中的类型判断(二)

前言

类型判断是框架设计的基础之一,它很重要,并且掌握类型判断对JavaScript的深入是必不可少的,这也是我为什么记录下这里我所理解的 JS 类型判断。

在上一节中说到typeof,即判断变量类型的操作符。从它的判断结果可以看出对于引用类型变量的判断都返回object字符串,由此引出instanceof。

instanceof

  • instance中文翻译为实例,通俗来讲就是判断对象是谁的实例。实例就牵扯到了构造函数和对象的继承。它的原理就是根据原型链进行搜寻。如obj1 instanceof obj2,从obj1原型链上查找是否存在obj2的原型属性。如果存在返回true。
  • instanceof是对象操作符,即用来判断对象,形式为 obj1 instanceof obj2(obj1是否是obj2的实例),obj2必须为对象,否则会报错。

    instanceof原理

    一、作用:
    1.用于判断某个实例是否属于某构造函数
    2.在继承关系中,用来判断一个实例是否属于它的父类型实例或者祖先类型的实例
    说白了,只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false

二、语法:
[对象] instanceof [构造函数]

1
2
let obj = new Object()
obj instanceof Object

三、涉及的构造函数
基础类型:String、Number、Boolean、Undefined、Null、Symbol
复杂类型:Array,Object
其他类型:Function、RegExp、Date
四、底层原理

1
2
3
4
5
6
7
8
9
10
11
12
13
function instance_of(L, R) {
let O = R.prototype
L = L.__proto__
while(true) {
if (L === null) {
return false
}
if (O === L) {
return true
}
L = L.__proto__
}
}

代码解释:

  • L表示对象实例,R表示构造函数或者父类型实例
  • 取R的显示原型,取L的隐式原型
  • 循环遍历进行判断第二步中的两个值是否相等,相等返回true,不相等继续查找L的原型链

五、未发生继承关系时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Cat(name,age,type){
this.name = name;
this.age = age;
this.type = type;
}
function Dog(name){
this.name = name;
}
var cats = new Cat('有鱼',2,'英短');
var dogs = new Dog('哈士奇');
console.log(cats instanceof Cat); // true
console.log(dogs instanceof Dog); // true
console.log(cats instanceof Object); // true
console.log(dogs instanceof Object); // true

先看一下“cats instanceof Cat”运行情况:

1
2
3
4
5
6
7
8
9
10
11
function instance_of(L, R) { // L即cats   R即Cat
var O = R.prototype; //O为Cat.prototype
L = L.__proto__; // L为cats._proto_
while (true) { //执行循环
if (L === null) //不通过
return false;
if (O === L) //判断:Cat.prototype ===cats._proto_
return true; //如果等于就返回true,证明cats是Cat类型
L = L.__proto__;
}
}

再看一下“cats instanceof Object”运行情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function instance_of(L, R) { //L即cats  R即Object     
var O = R.prototype; //O为Object.prototype
L = L.__proto__; // L为cats._proto_
while (true) { //执行循环
if (L === null) //不通过
return false;
if (O === L) // 此时判断Object.prototype === cats._proto_ 显然不成立
return true;
L = L.__proto__; //遍历cats的原型链,即此时L为 cats._proto_ ._proto_,
//即Cat.prototype._proto_指向的对象,
//接着执行循环,
//到Object .prototype === cats._proto_ ._proto_
//成立,返回true
}
}

六、产生继承关系时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Cat(name,age,type){
this.name = name;
this.age = age;
this.type = type;
}
function YingDuan(name,age,type,sex){
Cat.call(this,name,age,type);
this.sex = sex;
}
YingDuan.prototype = new Cat(); // 这里改变了原型指向,实现继承
var yd = new YingDuan("有鱼",2,"金渐层","男"); //创建了英短对象yd
console.log(yd instanceof YingDuan); // true
console.log(yd instanceof Cat); // true
console.log(yd instanceof Object); // true

先看一下“yd instanceof YingDuan”运行情况:

1
2
3
4
5
6
7
8
9
10
11
function instance_of(L, R) { //L即yd  R即YingDuan
var O = R.prototype; //O为YingDuan.prototype,现在指向了cat
L = L.__proto__; //L为yd._proto_,也随着prototype的改变而指向了cat
while (true) { //执行循环
if (L === null) //不通过
return false;
if (O === L) //判断是否 YingDuan.prototype ===yd._proto_
return true; //此时,两方都指Cat的实例对象cat,所以true
L = L.__proto__;
}
}

再看一下“yd instanceof Cat”运行情况,即如何判断yd继承了Cat:

1
2
3
4
5
6
7
8
9
10
11
function instance_of(L, R) { // L即yd  R即Cat  
var O = R.prototype; // O为Cat.prototype
L = L.__proto__; //L为yd._proto_,现在指向的是cat实例对象
while (true) { // 执行循环
if (L === null) //不通过
return false;
if (O === L) //判断是否 Cat.prototype === yd._proto_
return true; //此时,yd._proto_ 指向cat实例对象,并不满足
L = L.__proto__; //令L= yd._proto_._proto_,执行循环
} //yd._proto_ ._proto_,指的就是Cat.prototype,所以也返回true
} //这就证明了yd继承了Cat

总结

想必到这里大家也都明白两者的含义和用法,总之,typeof和instanceof都是用来判断变量类型的,两者的区别在于:

  • typeof判断所有变量的类型,返回值有number,boolean,string,function,object,undefined。
  • typeof对于丰富的对象实例,只能返回”Object”字符串。
  • instanceof用来判断对象,代码形式为obj1 instanceof obj2(obj1是否是obj2的实例),obj2必须为对象,否则会报错!其返回值为布尔值。
  • instanceof可以对不同的对象实例进行判断,判断方法是根据对象的原型链依次向下查询,如果obj2的原型属性存在obj1的原型链上,(obj1 instanceof obj2)值为true。