• 欢迎访问天天编码网站,Java技术、技术书单、开发工具,欢迎加入天天编码
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏天天编码吧
  • 我们的淘宝店铺已经开张了哦,传送门:https://shop145764801.taobao.com/

7.10 类检查,instanceof

JS 教程 tiantian 427次浏览 0个评论 扫描二维码

那个instanceof操作符用来检测某个对象是否属于某个特定的类。它会将继承性纳入考虑范围。

这样的一个检查在很多情况下非常实用,此处我们将使用该操作符来建立一个多态的函数,它会根据它们类型的不同来区别对待它们。

instanceof 操作符

语法为:

obj instanceof Class

obj属于Class或者它的父类时,就返回true

举例:

class Rabbit {}
let rabbit = new Rabbit();

// is it an object of Rabbit class?
alert( rabbit instanceof Rabbit ); // true

它同样可以与构造器函数配合使用:

// instead of class
function Rabbit() {}

alert( new Rabbit() instanceof Rabbit ); // true

当然,也能正确地处理内建类,比如Array

let arr = [1, 2, 3];
alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true

请注意,arr同样属于Object类。这是因为Array原型上继承自Object

那个instanceof操作符会检查那个原型链来做检查,而且也可以很好地配合静态方法Symbol.hasInstance使用。

那个obj instanceof Class算法的工作流程大概如下:

  1. 如果存在静态方法Symbol.hasInstance,那么就使用该方法,比如:
// assume anything that canEat is an animal
class Animal {
  static [Symbol.hasInstance](obj) {
    if (obj.canEat) return true;
  }
}

let obj = { canEat: true };
alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) is called
  1. 绝大多数的类都没有Symbol.hasInstance。在此种情况下,在obj的原型链中检查是否有一个原型等于Class.prototype

换句话说,就是检查:

obj.__proto__ === Class.prototype
obj.__proto__.__proto__ === Class.prototype
obj.__proto__.__proto__.__proto__ === Class.prototype
...

在上述示例中,Rabbit.prototype === rabbit.__proto__,所有它很快就给出了答案。

在下面的那个继承示例中,rabbit同样是一个父类的实例:

class Animal {}
class Rabbit extends Animal {}

let rabbit = new Rabbit();
alert(rabbit instanceof Animal); // true
// rabbit.__proto__ === Rabbit.prototype
// rabbit.__proto__.__proto__ === Animal.prototype (match!)

下图就是一个比较示例:

7.10 类检查,instanceof

另外,还存在另一个方法objA.isPrototypeOf(objB),当objA位于objB的原型链的某个位置时返回true。所以,obj instanceof Class测试可以重写为Class.prototype.isPrototypeOf(obj)

有趣的一点是:Class构造器本身不参与到这个检查,只有Class.prototype和它的原型链才参与检查。

prototype发生变化时,这就导致某些有趣的现象。

function Rabbit() {}
let rabbit = new Rabbit();

// changed the prototype
Rabbit.prototype = {};

// ...not a rabbit any more!
alert( rabbit instanceof Rabbit ); // false

这是避免修改prototype的一个原因。随意修改会导致安全问题。

好处:Object toString

我们已知,普通对象转换为字符串时,会转变成为[object Object]:

let obj = {};

alert(obj); // [object Object]
alert(obj.toString()); // the same

这是因为它们的toString就是如此实现。但是,存在一个隐藏的特性可以使得toString实际上更加强大。我们可以使用它作为typeof的扩展,并作为instanceof的另一个解决方案。

根据定义,那个内建的toString可以从对象中抽取出来,并在任何值的上下文中进行执行。而且它的结果取决于那个值。

  • 对于数值,它可以是[object Number].
  • 对于布尔值,它可以是[object Boolean]
  • 对于 null[object Null].
  • 对于 undefined[object Undefeind].
  • 对于数组,[object Array]

我们来演示:

// copy toString method into a variable for convenience
let objectToString = Object.prototype.toString;

// what type is this?
let arr = [];

alert( objectToString.call(arr) ); // [object Array]

此处,我们使用了在装饰器和转发,call和apply章节的call 调用来在this=arr上下文中执行objectToString函数。

在内部,那个toString算法会检查this,并且返回相应的结果。更多实例:

let s = Object.prototype.toString;

alert( s.call(123) ); // [object Number]
alert( s.call(null) ); // [object Null]
alert( s.call(alert) ); // [object Function]

Symbol.toStringTag

Object toString的行为可以可定制化,只需使用一个特殊的对象属性Symbol.toStringTag

举例:

let user = {
  [Symbol.toStringTag]: "User"
};

alert( {}.toString.call(user) ); // [object User]

对于绝大多数的环境相关的对象,存在一个如此的属性。下面是几个浏览器特定的示例:

// toStringTag for the envinronment-specific object and class:
alert( window[Symbol.toStringTag]); // window
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest

alert( {}.toString.call(window) ); // [object Window]
alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]

正如你所见,结果正是Symbol.toStringTag(如果存在),并包装在[object ...]中。

在最后,我们的“typeof”不仅仅工作于原始数据类型,而且适用于内建对象,还可以进行定制化。

对于内建对象,当我们希望以字符串的格式来获取类型,而不仅仅是检查它时,就可以代替instanceof使用。

总结

让我们再一次总结一下已知的类型检查方法:

方法 使用范围 返回
typeof 原始类型 字符串
{}.toString 原始类型,内建对象,具有Symbol.toStringTag 的对象 字符串
instanceof 对象 true/false

正如所见,{}.toString在技术上是一个更加高级的typeof

此外,instanceof的适用场景是处理具有类继承层级的情况,而且想将继承性计入检查的范畴。

任务


奇怪的 instanceof

为什么下列的instanceof返回true?我们可以轻易地发现a并不是由B()创建的。

function A() {}
function B() {}

A.prototype = B.prototype = {};

let a = new A();

alert( a instanceof B ); // true


天天编码 , 版权所有丨本文标题:7.10 类检查,instanceof
转载请保留页面地址:http://www.tiantianbianma.com/instanceof.html/
喜欢 (1)
支付宝[多谢打赏]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址