JavaScript中的instanceof运算符是什么?

JavaScript中的instanceof关键字在第一次遇到时会相当混乱,因为人们倾向于认为JavaScript不是面向对象的编程语言。

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

的instanceof

左手边(LHS)操作数是右手边(RHS)操作数正在testing的实际对象,它是一个类的实际构造函数。 基本定义是:

 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) 

值得一提的是,如果对象inheritance自类的原型,那么instanceof计算为true:

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

p instanceof Person是真的,因为pPerson.prototypeinheritance。

根据OP的请求

我已经添加了一些示例代码和解释的小例子。

当你声明一个variables时,你给它一个特定的types。

例如:

 int i; float f; Customer c; 

以上显示了一些variables,即ifc 。 types是integerfloat和用户定义的Customer数据types。 上面的types可以用于任何语言,而不仅仅是JavaScript。 但是,当你声明一个variables的时候,你并没有显式地定义一个types, var x ,x可以是一个数字/string/一个用户定义的数据types。 那么,什么样的instanceof会检查对象,看它是否是上面指定的types,从而可以使用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是用Customertypes声明的。 我们已经新build了它,并检查它是否是Customertypes。 当然是,它返回true。 然后仍然使用Customer对象,我们检查它是否是一个String 。 不,绝对不是一个String我们新build了一个Customer对象而不是一个String对象。 在这种情况下,它返回false。

真的很简单!

到目前为止,任何一个评论都没有涉及到instanceof的一个重要方面:inheritance。 由于原型inheritance,使用instanceof进行评估的variables可能会为多个“types”返回true。

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

 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 = new Foo(); // Inherit prototype 

现在我们有几个“类”,让我们来创build一些实例,并找出它们的实例:

 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 

看到最后一行? 对一个函数的所有“新”调用都会返回一个从Objectinheritance的对象。 即使使用对象创build简写,情况也是如此:

 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 

我觉得理解任何对象都可以是一个MULTIPLEtypes的实例是很重要的,因为你我(错误地)认为你可以区分使用instanceof对象和对象。 最后这个例子清楚地表明一个函数一个对象。

如果你正在使用任何inheritance模式,并且想通过除鸭子input之外的方法来确认一个对象的后代,这也是重要的。

希望能帮助任何人探索instanceof

这里的其他答案是正确的,但是他们并没有深入了解实际操作的instanceof ,这可能是一些语言律师感兴趣的。

JavaScript中的每个对象都有一个原型,可以通过__proto__属性访问。 函数也有一个prototype属性,它是由它们创build的任何对象的初始__proto__ 。 当一个函数被创build时,它被赋予一个独特的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 

我认为值得注意的是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中,而不是将其设置为返回值。 我认为这更好地显示了新关键字的作用;

 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,而不使用它赋值返回值。

您可以使用它来进行error handling和debugging,如下所示:

 try{ somefunction(); } catch(error){ if (error instanceof TypeError) { // Handle type Error } else if (error instanceof ReferenceError) { // Handle ReferenceError } else { // Handle all other error types } } 
 //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); 

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

instanceof在生产代码中很less用到,但是在你想要声明你的代码返回/创build正确types的对象的testing中很有用。 通过明确你的代码返回/创build的对象types,你的testing作为理解和logging你的代码的工具变得更加强大。

我想,我刚刚find了一个真实世界的应用程序,现在会更频繁地使用它。

如果你使用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 

在我的情况下,函数需要计算所有的东西(通过button上的点击事件)或只有一个特定的元素。 我使用的代码:

 var recalc = function (el) { el = (el == undefined || el instanceof $.Event) ? $('span.allItems') : $(el); // calculate... }; 

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中不存在的类。 尽pipeclass关键字不在ES2015中,因为class再次只是语法糖…但这是另外一个故事。