欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript的instanceof运算符学习教程

程序员文章站 2022-06-14 11:20:30
语法 object instanceof constructor 参数 object: 要检测的对象. constructor: 某个构造函...

语法

object instanceof constructor

参数
object:
要检测的对象.
constructor:
某个构造函数

描述:
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

// 定义构造函数
function c(){} 
function d(){} 

var o = new c();

// true,因为 object.getprototypeof(o) === c.prototype
o instanceof c; 

// false,因为 d.prototype不在o的原型链上
o instanceof d; 

o instanceof object; // true,因为object.prototype.isprototypeof(o)返回true
c.prototype instanceof object // true,同上

c.prototype = {};
var o2 = new c();

o2 instanceof c; // true

o instanceof c; // false,c.prototype指向了一个空对象,这个空对象不在o的原型链上.

d.prototype = new c(); // 继承
var o3 = new d();
o3 instanceof d; // true
o3 instanceof c; // true

需要注意的是,如果表达式 obj instanceof foo 返回true,则并不意味着该表达式会永远返回ture,因为foo.prototype属性的值有可能会改变,改变之后的值很有可能不存在于obj的原型链上,这时原表达式的值就会成为false。另外一种情况下,原表达式的值也会改变,就是改变对象obj的原型链的情况,虽然在目前的es规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的__proto__魔法属性,是可以实现的。比如执行obj.__proto__ = {}之后,obj instanceof foo就会返回false了。

instanceof和多全局对象(多个frame或多个window之间的交互)

在浏览器中,我们的脚本可能需要在多个窗口之间进行交互。多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。这可能会引发一些问题。比如,表达式 [] instanceof window.frames[0].array 会返回false,因为 array.prototype !== window.frames[0].array.prototype,因此你必须使用 array.isarray(myobj) 或者 object.prototype.tostring.call(myobj) === "[object array]"来判断myobj是否是数组。

示例
instanceof的常规用法是判断a是否是b类型:

console.log(true instanceof boolean); // false 
console.log(new number(1) instanceof number); // true

instanceof还能判断父类型:

function father() {}
function child() {}
child.prototype = new father();
var a = new child();
console.log(a instanceof child); // true
console.log(a instanceof father); // true

child构造函数继承自father,实例a是child构造的无疑,但是为何也是father的实例呢?其实instanceof运算符的内核可以简单地用以下代码描述:

function check(a, b) {
 while(a.__proto__) {
  if(a.__proto__ === b.prototype)
   return true;
  a = a.__proto__;
 }
 return false;
}

function foo() {}
console.log(object instanceof object === check(object, object)); // true 
console.log(function instanceof function === check(function, function)); // true 
console.log(number instanceof number === check(number, number)); // true 
console.log(string instanceof string === check(string, string)); // true 
console.log(function instanceof object === check(function, object)); // true 
console.log(foo instanceof function === check(foo, function)); // true 
console.log(foo instanceof foo === check(foo, foo)); // true

简单地说,a如果是b的实例,那么a肯定能使用b的prototype中定义的方法和属性,那么用代码表示就是a的原型链中有b.prototype取值相同的对象,于是顺着a的原型链一层层找就行了。

另外值得注意的是,string number boolean 以及function等都是函数,而函数则是统一由function构造而来的,so它们和任何单纯的函数一样,能用function上的原型属性:

function.prototype.a = 10;
console.log(string.a); // 10

最后来简单讲讲最开始的两道题吧。

 // 为了方便表述,首先区分左侧表达式和右侧表达式
 functionl = function, functionr = function; 
 // 下面根据规范逐步推演
 o = functionr.prototype = function.prototype 
 l = functionl.__proto__ = function.prototype 
 // 第一次判断
 o == l 
 // 返回 true

// 为了方便表述,首先区分左侧表达式和右侧表达式
 stringl = string, stringr = string; 
 // 下面根据规范逐步推演
 o = stringr.prototype = string.prototype 
 l = stringl.__proto__ = function.prototype 
 // 第一次判断
 o != l
 // 循环再次查找 l 是否还有 __proto__ 
 l = string.prototype.__proto__ = object.prototype 
 // 第二次判断
 o != l 
 // 再次循环查找 l 是否还有 __proto__ 
 l = string.prototype.__proto__ = null 
 // 第三次判断
 l == null 
 // 返回 false