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

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


当前回答

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只是语法糖…但那是另一个故事了。

其他回答

运算符

左手边(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。

真的就是这么简单!

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

你可以用它来进行错误处理和调试,就像这样:

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只是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只是语法糖…但那是另一个故事了。

在“什么时候合适,什么时候不合适?”这个问题上,我的观点是:

Instanceof在生产代码中很少有用,但在希望断言代码返回/创建正确类型的对象的测试中很有用。通过明确您的代码返回/创建的对象类型,您的测试作为理解和记录代码的工具变得更加强大。