第一次遇到JavaScript中的instanceof关键字时,可能会让人非常困惑,因为人们倾向于认为JavaScript不是面向对象的编程语言。
是什么? 它能解决什么问题? 什么时候合适,什么时候不合适?
第一次遇到JavaScript中的instanceof关键字时,可能会让人非常困惑,因为人们倾向于认为JavaScript不是面向对象的编程语言。
是什么? 它能解决什么问题? 什么时候合适,什么时候不合适?
当前回答
这里的其他答案是正确的,但它们没有涉及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
其他回答
你可以用它来进行错误处理和调试,就像这样:
try{
somefunction();
}
catch(error){
if (error instanceof TypeError) {
// Handle type Error
} else if (error instanceof ReferenceError) {
// Handle ReferenceError
} else {
// Handle all other error types
}
}
这里的其他答案是正确的,但它们没有涉及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
我认为值得注意的是,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变量中,而不仅仅是将其设置为返回值。我认为这更好地展示了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,而不使用它则赋给返回值。
到目前为止,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来区分对象和函数。最后一个例子清楚地显示了函数是一个对象。
如果您正在使用任何继承模式,并希望通过鸭子类型以外的方法确认对象的后代,这也很重要。
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只是语法糖…但那是另一个故事了。