JavaScript中的instanceof运算符是什么?

Alo*_*kin 303 javascript instanceof operators

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

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

Jon*_*onH 269

的instanceof

左侧(LHS)操作数是被测试到右侧(RHS)操作数的实际对象,该操作数是类的实际构造函数.基本定义是:

Checks the current object and returns true if the object
is of the specified object type.
Run Code Online (Sandbox Code Playgroud)

以下是一些很好的示例,这是一个直接从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)
Run Code Online (Sandbox Code Playgroud)

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

var p = new Person("Jon");
p instanceof Person
Run Code Online (Sandbox Code Playgroud)

这是p instanceof Person真的,因为p继承自Person.prototype.

根据OP的要求

我添加了一个带有一些示例代码和解释的小例子.

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

例如:

int i;
float f;
Customer c;
Run Code Online (Sandbox Code Playgroud)

上面显示一些变量,即i,fc.类型是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!
Run Code Online (Sandbox Code Playgroud)

上面我们已经看到了c声明的类型Customer.我们已经新了,并检查它是否是类型Customer.当然,它返回true.然后仍然使用Customer我们检查的对象是否是String.不,绝对不是String我们新建的Customer对象而不是String对象.在这种情况下,它返回false.

真的很简单!


web*_*sto 94

到目前为止,在任何评论中都没有涉及到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;
Run Code Online (Sandbox Code Playgroud)

现在我们有几个"类"让我们做一些实例,并找出它们的实例:

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
Run Code Online (Sandbox Code Playgroud)

看到最后一行?对函数的所有"新"调用都返回一个继承自Object的对象.即使使用对象创建速记,这也适用:

alert( 
    "Q: Is {} an instance of Object? "
+   "A: " + ( {} instanceof Object ) 
); // -> true
Run Code Online (Sandbox Code Playgroud)

那么"阶级"定义本身呢?它们的实例是什么?

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
Run Code Online (Sandbox Code Playgroud)

我觉得理解任何对象都可以是MULTIPLE类型的实例很重要,因为我(错误地)假设你可以通过使用来区分,说和对象和函数instanceof.最后一个例子清楚地表明函数一个对象.

如果您使用任何继承模式并希望通过除duck-typing之外的方法确认对象的后代,这也很重要.

希望有助于任何人探索instanceof.


Jay*_*rod 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__;
  }
}
Run Code Online (Sandbox Code Playgroud)

这基本上是对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
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是,IE中不允许直接操作"__proto__`"属性.如果我没记错的话,ECMA规范中不包括对财产的直接操纵,因此除了学术追求之外,将其用于任务可能是个坏主意. (5认同)
  • 无论用户代码是否可以访问,理解__proto__属性的隐含存在都很重要.+10如果我可以引用规范,这正是我来这里寻找的. (4认同)
  • 为了获得原型链接,使用`Object.getPrototypeOf(o)`,这将与您描述的`__proto__`相同,但符合ECMAScript. (3认同)
  • 旧版本不是100%肯定.听起来像这里(http://stackoverflow.com/questions/8413505/proto-for-ie9-or-ie10),在IE9中,它至少是可读的(尽管不可变).另外值得注意的是,听起来浏览器可能会完全放弃它. (2认同)

Ste*_*ger 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)
Run Code Online (Sandbox Code Playgroud)

他没有提到的是这个;

var color1 = String("green");
color1 instanceof String; // returns false
Run Code Online (Sandbox Code Playgroud)

指定"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'
Run Code Online (Sandbox Code Playgroud)

使用"new"将函数内部的"this"值赋给声明的var,而不使用它则指定返回值.

  • Date.getTime()//失败.是的,新的很重要. (3认同)
  • 使用任何JavaScript类型的`new`是没有意义的,这使得接受的答案对初学者来说更加困惑.`text = String('test')`和`options = {}`不会被`instanceof`测试,而是用`typeof`来测试. (2认同)

Tar*_*ied 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
    }
}
Run Code Online (Sandbox Code Playgroud)


Wil*_*een 6

它是什么?

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

obj instanceof testObj;
Run Code Online (Sandbox Code Playgroud)
  1. 检查对象的原型是否等于构造函数的原型:obj.__proto__ === testObj.prototype >> 如果是则true instanceof返回true
  2. 会沿着原型链往上爬。例如:obj.__proto__.__proto__ === testObj.prototype >> 如果这是true instanceof将返回true
  3. 将重复步骤 2,直到检查完对象的完整原型。如果对象的原型链上没有任何地方与testObj.prototypethen运算符相匹配instanceof,则返回false

例子:

它解决什么问题?

它解决了方便地检查对象是否源自某个原型的问题。例如,当一个函数接收一个可以具有各种原型的对象时。然后,在使用原型链中的方法之前,我们可以使用instanceof运算符来检查这些方法是否在对象上。

例子:

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
Run Code Online (Sandbox Code Playgroud)

talk()函数中,首先检查原型是否位于对象上。之后,选择适当的方法来执行。不进行此检查可能会导致执行不存在的方法,从而导致引用错误。

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

我们已经讨论过这个了。当您需要在使用对象执行某些操作之前检查对象的原型时,请使用它。