JavaScript中的instanceof运算符是什么?

时间:2010-03-15 17:50:19

标签: javascript operators instanceof

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

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

11 个答案:

答案 0 :(得分:255)

的instanceof

左侧(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)

值得一提的是instanceof如果对象继承自classe的原型,则求值为true:

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

由于p instanceof Person继承自p,因此Person.prototype为真。

根据OP的要求

我添加了一个小示例,其中包含一些示例代码和解释。

声明变量时,请为其指定特定类型。

例如:

int i;
float f;
Customer c;

以上显示了一些变量,即ifc。类型为integerfloat和用户定义的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。

真的很简单!

答案 1 :(得分:91)

到目前为止,任何评论似乎都没有涉及到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

答案 2 :(得分:86)

这里的其他答案是正确的,但他们没有深入了解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__;
  }
}

这基本上是对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

答案 3 :(得分:45)

我认为值得注意的是,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,而不使用它则指定返回值。

答案 4 :(得分:8)

您可以将它用于错误处理和调试,如下所示:

try{
    somefunction();
} 
catch(error){
    if (error instanceof TypeError) {
        // Handle type Error
    } else if (error instanceof ReferenceError) {
        // Handle ReferenceError
    } else {
        // Handle all other error types
    }
}

答案 5 :(得分:3)

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

答案 6 :(得分:1)

关于问题&#34;什么时候适当?什么时候不适合?&#34;,我的2美分:

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

答案 7 :(得分:1)

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再次只是语法糖......但这是另一个故事。

答案 8 :(得分:1)

  

这是什么?

Javascript是一种原型语言,这意味着它使用原型进行“继承”。 instanceof运算符测试对象的prototype链中是否存在构造函数的__proto__属性。这意味着它将执行以下操作(假设testObj是一个函数对象):

obj instanceof testObj;
  1. 检查对象的原型是否等于构造函数的原型:obj.__proto__ === testObj.prototype >>如果是true instanceof将返回true
  2. 将攀登原型链。例如:obj.__proto__.__proto__ === testObj.prototype >>如果是true instanceof将返回true
  3. 将重复步骤2,直到检查了对象的完整原型为止。如果对象原型链上的任何地方都没有与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()函数中的原型是否位于对象上。此后,将选择适当的方法来执行。不执行此检查可能导致执行不存在的方法,从而导致引用错误。

  

什么时候合适,什么时候不合适?

我们已经解决了这个问题。当您需要在处理对象原型之前对其进行检查时,请使用它。

答案 9 :(得分:0)

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

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

在我的情况下,函数需要为所有(通过按钮上的单击事件)或仅一个特定元素计算某些内容。我使用的代码:

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

答案 10 :(得分:0)

@SebastianSimon 我的最后一个答案是 8 岁(当我跛脚时),我可能写了一些牛*命中:)

简而言之 - 目前我使用 instanceof 的唯一情况是我使用 class 实例和行为取决于我将收到的类,例如。我想区分 404 是 ErrorA(资源不存在)还是 ErrorB(未找到服务) - 库响应代码令人困惑,但幸运的是它使用不同的错误类抛出。

绝对(目前)我不会使用它来检查反映原语的类型 - 您无法确定库返回的是 'msg' 还是 new String('msg')

它们都有属于 String 类的方法,因为 'msg' 原语在内部被包装成字符串对象。内部意味着通过解释器。它们都是 Stringsinstanceof 运算符在这里似乎不够 - 检查是否......是原始类型或类,我会混合使用 typeof && instanceof - 但仅用于从外部 JS 库返回的内容。

Currenlty TypeScript 正在解决这个问题,您不再需要对 typeofinstanceof 使用此类恶意检查。