第一次遇到JavaScript中的instanceof关键字时,可能会让人非常困惑,因为人们倾向于认为JavaScript不是面向对象的编程语言。

是什么? 它能解决什么问题? 什么时候合适,什么时候不合适?


当前回答

是什么?

Javascript是一种原型语言,这意味着它使用原型进行“继承”。instanceof操作符测试构造函数的prototype属性类型是否存在于对象的__proto__链中。这意味着它将执行以下操作(假设testObj是一个函数对象):

obj instanceof testObj;

Check if prototype of the object is equal to the prototype of the constructor: obj.__proto__ === testObj.prototype >> if this is true instanceof will return true. Will climb up the prototype chain. For example: obj.__proto__.__proto__ === testObj.prototype >> if this is true instanceof will return true. Will repeat step 2 until the full prototype of object is inspected. If nowhere on the prototype chain of the object is matched with testObj.prototype then instanceof operator will return false.

例子:

人(名){ This.name = name; } var me =新人(“威廉”); console.log(me instanceof Person);/ /正确的 //因为:我。__proto__ === Person。Prototype //计算结果为true console.log(me instanceof Object);/ /正确的 // because: me.__proto__。__proto__ ===对象。Prototype //计算结果为true console.log(me instanceof Array);/ /错误 数组不在原型链上

它能解决什么问题?

它解决了方便地检查对象是否来自某个原型的问题。例如,当一个函数接收到一个可以有各种原型的对象时。然后,在使用原型链中的方法之前,我们可以使用instanceof操作符来检查这些方法是否在对象上。

例子:

function Person1 (name) { this.name = name; } function Person2 (name) { this.name = name; } Person1.prototype.talkP1 = function () { console.log('Person 1 talking'); } Person2.prototype.talkP2 = function () { console.log('Person 2 talking'); } function talk (person) { if (person instanceof Person1) { person.talkP1(); } if (person instanceof Person2) { person.talkP2(); } } const pers1 = new Person1 ('p1'); const pers2 = new Person2 ('p2'); talk(pers1); talk(pers2);

在talk()函数中,首先检查原型是否位于对象上。在此之后,选择适当的方法来执行。不进行此检查可能导致执行一个不存在的方法,从而导致引用错误。

什么时候合适,什么时候不合适?

我们已经讲过了。当您需要在对对象进行操作之前检查对象的原型时,可以使用它。

其他回答

这里的其他答案是正确的,但它们没有涉及instanceof的实际工作方式,这可能会引起一些语言律师的兴趣。

JavaScript中的每个对象都有一个原型,可以通过__proto__属性访问。函数也有一个prototype属性,它是由它们创建的任何对象的初始__proto__。当一个函数被创建时,它被赋予一个唯一的对象作为原型。instanceof操作符使用这种唯一性来给出答案。如果你把instanceof写成一个函数,它可能是这样的。

function instance_of(V, F) {
  var O = F.prototype;
  V = V.__proto__;
  while (true) {
    if (V === null)
      return false;
    if (O === V)
      return true;
    V = V.__proto__;
  }
}

这基本上是对ECMA-262 5.1版(也称为ES5)第15.3.5.3节的解释。

注意,可以将任何对象重新赋值给函数的prototype属性,也可以在构造对象后重新赋值对象的__proto__属性。这会给你一些有趣的结果:

function F() { }
function G() { }
var p = {};
F.prototype = p;
G.prototype = p;
var f = new F();
var g = new G();

f instanceof F;   // returns true
f instanceof G;   // returns true
g instanceof F;   // returns true
g instanceof G;   // returns true

F.prototype = {};
f instanceof F;   // returns false
g.__proto__ = {};
g instanceof G;   // returns false
//Vehicle is a function. But by naming conventions
//(first letter is uppercase), it is also an object
//constructor function ("class").
function Vehicle(numWheels) {
    this.numWheels = numWheels;
}

//We can create new instances and check their types.
myRoadster = new Vehicle(4);
alert(myRoadster instanceof Vehicle);

运算符

左手边(LHS)操作数是被测试到右手边(RHS)操作数的实际对象,右手边(RHS)操作数是类的实际构造函数。基本定义是:

检查当前对象,如果对象是指定的对象类型,则返回true。

这里有一些很好的例子,这里有一个直接取自Mozilla开发者网站的例子:

var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral"; //no type specified
color2 instanceof String; // returns false (color2 is not a String object)

值得一提的是,如果对象继承了类的原型,instanceof的值为true:

var p = new Person("Jon");
p instanceof Person

即p instanceof Person为真,因为p继承自Person.prototype。

根据指挥官的要求

I've added a small example with some sample code and an explanation.

当你声明一个变量时,你给它一个特定的类型。

例如:

int i;
float f;
Customer c;

上面显示了一些变量,即i, f和c。类型是整数,浮点数和用户定义的客户数据类型。像上面这样的类型可以适用于任何语言,而不仅仅是JavaScript。然而,在JavaScript中,当你声明一个变量时,你不会显式地定义一个类型,var x, x可以是一个数字/字符串/用户定义的数据类型。instanceof所做的是检查对象是否为指定的类型,因此从上面获取Customer对象,我们可以这样做:

var c = new Customer();
c instanceof Customer; //Returns true as c is just a customer
c instanceof String; //Returns false as c is not a string, it's a customer silly!

上面我们已经看到c是用Customer类型声明的。我们已经更新了,并检查了是否为客户类型。当然,它返回true。然后仍然使用Customer对象检查它是否是String对象。不,肯定不是String我们新建了Customer对象,不是String对象。在这种情况下,它返回false。

真的就是这么简单!

到目前为止,instanceof有一个重要的方面似乎没有在任何注释中提到:继承。由于原型继承,使用instanceof计算的变量对于多个“类型”可能返回true。

例如,让我们定义一个类型和一个子类型:

function Foo(){ //a Foo constructor
    //assign some props
    return this;
}

function SubFoo(){ //a SubFoo constructor
    Foo.call( this ); //inherit static props
    //assign some new props
    return this;
}

SubFoo.prototype = Object.create(Foo.prototype); // Inherit prototype
SubFoo.prototype.constructor = SubFoo;

现在我们有了几个“类”,让我们创建一些实例,并找出它们是什么实例:

var 
    foo = new Foo()
,   subfoo = new SubFoo()
;

alert( 
    "Q: Is foo an instance of Foo? "
+   "A: " + ( foo instanceof Foo ) 
); // -> true

alert( 
    "Q: Is foo an instance of SubFoo? " 
+   "A: " + ( foo instanceof SubFoo ) 
); // -> false

alert( 
    "Q: Is subfoo an instance of Foo? "
+   "A: " + ( subfoo instanceof Foo ) 
); // -> true

alert( 
    "Q: Is subfoo an instance of SubFoo? "
+   "A: " + ( subfoo instanceof SubFoo ) 
); // -> true

alert( 
    "Q: Is subfoo an instance of Object? "
+   "A: " + ( subfoo instanceof Object ) 
); // -> true

看到最后一行了吗?所有对函数的“new”调用都会返回一个继承自object的对象。即使在使用对象创建简写时也是如此:

alert( 
    "Q: Is {} an instance of Object? "
+   "A: " + ( {} instanceof Object ) 
); // -> true

那么“类”定义本身呢?它们是什么实例?

alert( 
    "Q: Is Foo an instance of Object? "
+   "A:" + ( Foo instanceof Object) 
); // -> true

alert( 
    "Q: Is Foo an instance of Function? "
+   "A:" + ( Foo instanceof Function) 
); // -> true

我觉得理解任何对象都可以是MULTIPLE类型的实例是很重要的,因为你可能(错误地)假设你可以通过使用instanceof来区分对象和函数。最后一个例子清楚地显示了函数是一个对象。

如果您正在使用任何继承模式,并希望通过鸭子类型以外的方法确认对象的后代,这也很重要。

是什么?

Javascript是一种原型语言,这意味着它使用原型进行“继承”。instanceof操作符测试构造函数的prototype属性类型是否存在于对象的__proto__链中。这意味着它将执行以下操作(假设testObj是一个函数对象):

obj instanceof testObj;

Check if prototype of the object is equal to the prototype of the constructor: obj.__proto__ === testObj.prototype >> if this is true instanceof will return true. Will climb up the prototype chain. For example: obj.__proto__.__proto__ === testObj.prototype >> if this is true instanceof will return true. Will repeat step 2 until the full prototype of object is inspected. If nowhere on the prototype chain of the object is matched with testObj.prototype then instanceof operator will return false.

例子:

人(名){ This.name = name; } var me =新人(“威廉”); console.log(me instanceof Person);/ /正确的 //因为:我。__proto__ === Person。Prototype //计算结果为true console.log(me instanceof Object);/ /正确的 // because: me.__proto__。__proto__ ===对象。Prototype //计算结果为true console.log(me instanceof Array);/ /错误 数组不在原型链上

它能解决什么问题?

它解决了方便地检查对象是否来自某个原型的问题。例如,当一个函数接收到一个可以有各种原型的对象时。然后,在使用原型链中的方法之前,我们可以使用instanceof操作符来检查这些方法是否在对象上。

例子:

function Person1 (name) { this.name = name; } function Person2 (name) { this.name = name; } Person1.prototype.talkP1 = function () { console.log('Person 1 talking'); } Person2.prototype.talkP2 = function () { console.log('Person 2 talking'); } function talk (person) { if (person instanceof Person1) { person.talkP1(); } if (person instanceof Person2) { person.talkP2(); } } const pers1 = new Person1 ('p1'); const pers2 = new Person2 ('p2'); talk(pers1); talk(pers2);

在talk()函数中,首先检查原型是否位于对象上。在此之后,选择适当的方法来执行。不进行此检查可能导致执行一个不存在的方法,从而导致引用错误。

什么时候合适,什么时候不合适?

我们已经讲过了。当您需要在对对象进行操作之前检查对象的原型时,可以使用它。