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

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


当前回答

我刚刚发现了一个真实的应用程序,我想现在会更经常地使用它。

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

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...
};

其他回答

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

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是在声明对象时使用“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来区分对象和函数。最后一个例子清楚地显示了函数是一个对象。

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

@SebastianSimon我最后的答案是8岁(那时我跛了),有可能我写了一些牛逼的东西:)

简单地说——目前我使用instanceof的唯一情况是当我使用类实例时,行为取决于我将接收的类,例如。我想区分404是否为ErrorA(资源不存在)或ErrorB(服务未找到)-库响应代码令人困惑,但我的运气是使用不同的错误类抛出。

当然(目前)我不会用它来检查反映原语的类型——你不能确定库是否返回'msg'或new String('msg')。

它们都有属于String类的方法,因为'msg'原语在内部包装成字符串对象。内部是指通过解释器。它们都是字符串,但instanceof操作符似乎在这里是不够的-检查某事物是否是原始或类,我会使用typeof && instanceof的混合-但仅用于从外部JS库返回的东西。

目前TypeScript正在解决这个问题,你不再需要使用typeof和instanceof这样繁琐的检查。

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