JavaScript中的instanceof
关键字在第一次遇到时会非常混乱,因为人们倾向于认为JavaScript不是面向对象的编程语言。
左侧(LHS)操作数是被测试到右侧(RHS)操作数的实际对象,该操作数是类的实际构造函数。基本定义是:
Checks the current object and returns true if the object
is of the specified object type.
这里有一些good examples,这是一个直接从Mozilla's developer site采取的例子:
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)
值得一提的是,如果对象继承自classe的原型,则instanceof
的计算结果为true:
var p = new Person("Jon");
p instanceof Person
这是p instanceof Person
是真的,因为p
继承自Person.prototype
。
我添加了一个带有一些示例代码和解释的小例子。
声明变量时,为其指定特定类型。
例如:
int i;
float f;
Customer c;
以上显示了一些变量,即i
,f
和c
。类型是integer
,float
和用户定义的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。
真的很简单!
我认为,我刚刚找到了一个真实世界的应用程序并且现在会更频繁地使用它。
如果你使用jQuery事件,有时你想编写一个更通用的函数,也可以直接调用(没有事件)。你可以使用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
的一个实例并做出适当的反应。
var recalc = function (el) {
el = (el == undefined || el instanceof $.Event) ? $('span.allItems') : $(el);
// calculate...
};
在我的例子中,函数需要为所有(通过按钮上的单击事件)或仅一个特定元素计算某些内容。我用过的代码:
qazxswpoi
到目前为止,在任何评论中都没有涉及到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 = new Foo(); // Inherit prototype
现在我们有几个“类”让我们做一些实例,并找出它们的实例:
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
来区分,说和对象和函数。最后一个例子清楚地表明函数是一个对象。
如果您使用任何继承模式并希望通过除duck-typing之外的方法确认对象的后代,这也很重要。
希望有助于任何人探索instanceof
。
这里的其他答案是正确的,但他们没有深入了解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__;
}
}
的样子。
prototype
这基本上是对ECMA-262版本5.1(也称为ES5)第15.3.5.3节的解释。
请注意,您可以将任何对象重新分配给函数的__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
属性后重新分配该对象。这会给你一些有趣的结果:
var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral";
color2 instanceof String; // returns false (color2 is not a String object)
我认为值得注意的是,instanceof是在声明对象时使用“new”关键字定义的。在JonH的例子中;
var color1 = String("green");
color1 instanceof String; // returns false
他没有提到的是这个;
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”实际上将String构造函数的结束状态复制到color1 var中,而不是仅将其设置为返回值。我认为这更能说明新关键字的作用;
try{
somefunction();
}
catch(error){
if (error instanceof TypeError) {
// Handle type Error
} else if (error instanceof ReferenceError) {
// Handle ReferenceError
} else {
// Handle all other error types
}
}
使用“new”将函数内部的“this”值赋给声明的var,而不使用它则指定返回值。
您可以将它用于错误处理和调试,如下所示:
//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);
instanceof
它是什么?
Javascript是一种原型语言,这意味着它使用原型进行“继承”。 prototype
运算符测试构造函数的__proto__
属性是否存在于对象的obj instanceof testObj;
链中。这意味着它将执行以下操作(假设testObj是一个函数对象):
obj.__proto__ === testObj.prototype
true
>>如果这是instanceof
true
将返回obj.__proto__.__proto__ === testObj.prototype
。true
>>如果这是instanceof
true
将返回testObj.prototype
。instanceof
匹配,那么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()
在instanceof
函数中,首先检查原型是否位于对象上。在此之后,选择适当的方法来执行。不执行此检查可能导致执行不存在的方法,从而导致引用错误。
什么时候适当,什么时候不适合?
我们已经过去了。在使用它之前需要检查对象的原型时使用它。
关于“什么时候适当,什么时候不适合?”的问题,我的2美分:
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
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
只取决于对象构造函数的原型。
构造函数只是一个普通的函数。严格来说它是一个函数对象,因为一切都是Javascript中的对象。而且这个函数对象有一个原型,因为每个函数都有一个原型。
原型只是一个普通对象,位于另一个对象的原型链中。这意味着在另一个对象的原型链中创建一个原型的对象:
instanceof
应该避免使用class
运算符,因为它伪造了Javascript中不存在的类。尽管class
关键字也不在ES2015中,因为instanceof
再次只是语法糖...但这是另一个故事。