JavaScript中的instanceof运算子是什么?


313

instanceof最初遇到JavaScript时,该关键字可能会造成很大的混乱,因为人们倾向于认为JavaScript不是一种面向对象的编程语言。

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

3
尽管下面的答案非常有用,但您在实词应用程序中不会使用太多(至少我不会使用)。可以使object.type属性包含一个字符串并进行检查。
奥马尔·伊萨维

4
JS毫无意义:"foo" instanceof String=>假,1 instanceof Number=>假,{} instanceof Object=>假。说什么?!
morbusg

12
@morbusg您的评论有误导性。首先"foo" instanceof String => false是正确的,因为typeof "foo" == 'string'new String("foo") instanceof String => true,因为typeof String == 'function'-您应该将函数视为类(类的定义)。将其分配为时,变量变为instanceof某些function(类)var v = new AnythingWhatTypeofEqualsFunction()。同样适用于1typeof 1 == 'number'- “号”是不是“功能” :)其次- {} instanceof ObjectTRUE在节点和现代浏览器
FIDER

1
@fider:那是对语言规范的评论,来自一位红宝石主义者。
morbusg 2013年

@morbusg- ({}) instanceof Object将返回true。实际上,您编写的代码会给您一个错误。
DDM

Answers:


279

实例

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

Checks the current object and returns true if the object
is of the specified object type.

这是一些很好的示例,这是直接从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

根据OP的要求

我添加了一个带有示例代码和解释的小示例。

声明变量时,可以为其指定特定类型。

例如:

int i;
float f;
Customer c;

上面显示一些变量,即ifc。类型为integerfloat由用户定义Customer数据类型。诸如此类的类型可以适用于任何语言,而不仅仅是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。我们已经对其进行了更新,并检查了它是否为类型Customer。当然可以,它返回true。然后仍然使用该Customer对象,我们检查它是否为String。不,绝对不是String我们更新的Customer对象而不是String对象。在这种情况下,它返回false。

真的就是这么简单!


@Alon-我为您添加了一个示例。参见上文,color1是字符串类型,因此当您说color1 instanceof String;这将返回true时,因为color1是字符串。
2010年

@Alon-它检查对象以查看它是什么类型的对象。考虑一个人/客户对象。所以person p = new person()p现在是一个人类型而不是一个字符串类型。
JonH

在JavaScript中,要理解变量具有在整个生命周期中具有不同类型的灵活性,可能会有些棘手。代码示例:jsfiddle.net/sikusikucom/znSPv
moey 2012年

@ Siku-Siku.Com-我没有看到任何技巧,var zero = 0; alert(zero); zero = "0"; alert(zero)我们从原始语言过渡intstring没有任何问题的原始语言。
JonH 2012年

哦,我的意思是,这是非常棘手/新来理解(不这样做),其“灵活性”在JavaScript中,ESP。对于某些习惯于需要例如显式转换来更改变量类型的语言的用户。正如您所指出的,将类型从原始类型更改int为原始类型非常容易string
moey 2012年

95

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

看到最后一行吗?对函数的所有“新”调用都返回一个从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。正如最后一个示例清楚地显示了一个功能对象。

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

希望对任何人有帮助instanceof


更棒的是,您从原型继承后,SubFoo.prototype = new Foo();可以向其添加更多方法,并且subfoo instanceof Foo检查仍将通过subfoo instanceof SubFoo
Cory Danielson 2014年

87

此处的其他答案是正确的,但它们并未instanceof涉及实际的工作方式,这对某些语言律师而言可能很有趣。

JavaScript中的每个对象都有一个原型,可以通过该__proto__属性访问。函数还具有一个prototype属性,该属性是__proto__它们创建的任何对象的初始名称。创建函数时,会为其提供一个唯一的对象prototype。该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

5
值得注意的是__proto__,IE中不允许直接操纵“ ”属性。如果我没记错的话,ECMA规范中也没有包含对该属性的直接操作,因此,除了学术上的追求外,将其用于任务分配可能不是一个好主意。
webnesto 2012年

@webnesto,是的,proto不在规范中。我不知道IE不支持它。当您说直接操作时,您是说它根本没有暴露于JS代码,还是只是不可写?
杰伊·康罗德

2
在旧版本上不是100%确定。听起来像从这里开始(stackoverflow.com/questions/8413505/proto-for-ie9-or-ie10)在IE9中至少是可读的(尽管不是可变的)。还值得注意的是,听起来浏览器可能会完全删除它。
webnesto 2012年

4
理解原型属性的隐含存在非常重要,无论用户代码是否可以访问它。如果我可以引用该规范,则+10,这正是我来这里寻找的内容。
Mike Edwards

3
为了获得原型链接,请使用Object.getPrototypeOf(o),它与__proto__您描述的相同,但符合ECMAScript。
froginvasion 2014年

45

我认为值得注意的是,instanceof是在声明对象时通过使用“ new”关键字定义的。在JonH的示例中;

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

他没有提到的是这个。

var color1 = String("green");
color1 instanceof String; // returns false

指定“ new”实际上将String构造函数的结束状态复制到color1 var中,而不仅仅是将其设置为返回值。我认为这更好地表明了new关键字的作用;

function Test(name){
    this.test = function(){
        return 'This will only work through the "new" keyword.';
    }
    return name;
}

var test = new Test('test');
test.test(); // returns 'This will only work through the "new" keyword.'
test // returns the instance object of the Test() function.

var test = Test('test');
test.test(); // throws TypeError: Object #<Test> has no method 'test'
test // returns 'test'

使用“ new”将函数内的“ this”值分配给声明的var,而不使用它分配返回值。


2
new与JavaScript的任何类型一起使用都没有意义,这会使初学者更加难以接受。text = String('test')options = {}不是通过instanceof而是通过测试typeof
瑞安

3
Date.getTime()//失败。是的,新的很重要。
Stephen Belanger

1
尝试在控制台中运行它。因为getTime()不存在,您会得到一个错误。您确实需要使用new。
Stephen Belanger

8

您可以将其用于错误处理和调试,如下所示:

try{
    somefunction();
} 
catch(error){
    if (error instanceof TypeError) {
        // Handle type Error
    } else if (error instanceof ReferenceError) {
        // Handle ReferenceError
    } else {
        // Handle all other error types
    }
}

3
//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);

3

它是什么?

Javascript是一种原型语言,这意味着它使用原型进行“继承”。所述instanceof,如果一个构造函数的操作者测试prototypepropertype存在于__proto__一个对象的链。这意味着它将执行以下操作(假设testObj是一个函数对象):

obj instanceof testObj;
  1. 检查对象的原型是否等于构造函数的原型:obj.__proto__ === testObj.prototype >>如果true instanceof返回,则返回true
  2. 将爬上原型链。例如:obj.__proto__.__proto__ === testObj.prototype >>如果这true instanceof将返回true
  3. 将重复步骤2,直到检查了对象的完整原型为止。如果对象原型链上的任何地方都没有与之匹配,testObj.prototypeinstanceof操作符将返回false

例:

function Person(name) {
  this.name = name;
}
var me = new Person('Willem');

console.log(me instanceof Person); // true
// because:  me.__proto__ === Person.prototype  // evaluates true

console.log(me instanceof Object); // true
// because:  me.__proto__.__proto__ === Object.prototype  // evaluates true

console.log(me instanceof Array);  // false
// because: Array is nowhere on the prototype chain

它解决什么问题?

它解决了方便地检查对象是否源自某个原型的问题。例如,当一个函数接收到一个可以具有各种原型的对象时。然后,在使用原型链中的方法之前,我们可以使用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()首先在函数中检查原型是否位于对象上。此后,将选择适当的方法来执行。不执行此检查可能导致执行不存在的方法,从而导致引用错误。

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

我们有点已经解决了这个问题。当您需要在处理某对象之前检查其原型时,可以使用它。


1
我认为您想写的不是“ 构造函数的原型出现在构造函数的prototype属性中的某个地方 ”的其他内容
Bergi

您可能要提及的是,让人们共享一个接口并命名这两种方法会更合适PersonX.prototype.talk,以便该talk功能可以轻松实现person.talk()
Bergi

您完全正确地对其进行了更新,因此定义更好。感谢您指出!
威廉·范德温

另外,请勿__proto__在文档中使用它,它已被弃用- Object.getPrototype()而是写一些东西
Bergi

1

关于“什么时候合适,什么时候不合适?”这个问题,我的2分钱是:

instanceof在生产代码中很少有用,但是在想要断言代码返回/创建正确类型的对象的测试中有用。通过明确说明代码将要返回/创建的对象的种类,测试将变得更加强大,可以作为理解和记录代码的工具。


1

instanceof仅仅是isPrototypeOf

function Ctor() {}
var o = new Ctor();

o instanceof Ctor; // true
Ctor.prototype.isPrototypeOf(o); // true

o instanceof Ctor === Ctor.prototype.isPrototypeOf(o); // equivalent

instanceof 仅仅取决于对象构造函数的原型。

构造函数只是一个普通的函数。严格来讲,它是一个函数对象,因为所有内容都是Javascript中的对象。这个函数对象有一个原型,因为每个函数都有一个原型。

原型只是一个普通对象,位于另一个对象的原型链中。这意味着在另一个对象的原型链中将成为原型的对象:

function f() {} //  ordinary function
var o = {}, // ordinary object
 p;

f.prototype = o; // oops, o is a prototype now
p = new f(); // oops, f is a constructor now

o.isPrototypeOf(p); // true
p instanceof f; // true

instanceof应避免使用运算符,因为它会伪造Javascript中不存在的类。尽管class在ES2015中也不使用关键字,但由于class它只是...的语法糖,但这是另一回事了。


1
第一行是不正确的!有关更多信息,请参见此处:“ isPrototypeOf()与instanceof运算符不同。在表达式“对象instanceof AFunction”中,将根据AFunction.prototype(而非AFunction本身)检查对象原型链。
Yan Foto 2016年

1
@Yan仍然instanceof是从派生的isPrototypeOf。我称这种语法糖。您的MDN来源是个玩笑,不是吗?

不。这不是,也不应该是个玩笑,仍然是错误的链接。我本来打算发布这个。我不想涉猎技术,但是instanceof 不想做与相同的事情isPrototypeOf。而已。
Yan Foto

0

我认为我只是找到了一个实际的应用程序,并且现在会更频繁地使用它。

如果您使用jQuery事件,有时您想编写一个更通用的函数,也可以直接调用它(不带事件)。您可以instanceof用来检查函数的第一个参数是否是的实例,jQuery.Event并做出适当的反应。

var myFunction = function (el) {                
    if (el instanceof $.Event) 
        // event specific code
    else
        // generic code
};

$('button').click(recalc);    // Will execute event specific code
recalc('myParameter');  // Will execute generic code

就我而言,该功能需要为所有内容(通过按钮上的click事件)或仅一个特定元素计算内容。我使用的代码:

var recalc = function (el) { 
    el = (el == undefined || el instanceof $.Event) ? $('span.allItems') : $(el);
    // calculate...
};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.