JavaScript 中的 instanceof 运算符是什么?

IT技术 javascript operators instanceof
2021-02-07 04:08:03

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

  • 它是什么?
  • 它解决了哪些问题?
  • 什么时候合适,什么时候不合适?
6个回答

实例

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

Checks the current object and returns true if the object
is of the specified object type.

这里有一些很好的例子,这里有一个直接取自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.

根据 OP 的要求

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

当你声明一个变量时,你会给它一个特定的类型。

例如:

int i;
float f;
Customer c;

上面显示一些变量,即ifc类型是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!

上面我们已经看到,它c是用类型声明的Customer我们已经对它进行了新的检查并检查了它是否属于类型Customer当然,它返回真。然后仍然使用该Customer对象,我们检查它是否是String. 不,绝对不是String我们更新了一个Customer对象而不是一个String对象。在这种情况下,它返回 false。

真的就是这么简单!

@Alon - 我为你添加了一个例子。见上文,color1 是字符串类型,所以当你说color1 instanceof String;这会返回 true,因为 color1 是一个字符串。
2021-03-19 04:08:03
哦,我的意思是理解(而不是)JavaScript 中的“灵活性”是很棘手的/新的,尤其是。对于一些习惯于需要例如显式转换来改变变量类型的语言的人。正如您所指出的,它很容易从原始例如更改类型int本原string
2021-03-24 04:08:03
@Siku-Siku.Com - 我没有看到任何技巧,var zero = 0; alert(zero); zero = "0"; alert(zero)我们从原始int到原始string没有任何问题。
2021-03-30 04:08:03
@Alon - 它检查一个对象以查看它是什么类型的对象。考虑一个人/客户对象。所以person p = new person()p 现在是个人类型而不是字符串类型。
2021-04-01 04:08:03
在 JavaScript 中,理解一个变量在其整个生命周期中具有不同类型的灵活性可能会很棘手。代码示例:jsfiddle.net/sikusikucom/znSPv
2021-04-05 04:08:03

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

看到最后一行了吗?对函数的所有“新”调用都返回一个从 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

更棒的是,从原型继承之后,SubFoo.prototype = new Foo();您可以向其添加更多方法,并且subfoo instanceof Foo检查仍然会通过subfoo instanceof SubFoo
2021-04-05 04:08:03

这里的其他答案是正确的,但它们没有instanceof涉及实际工作原理,这可能是一些语言律师感兴趣的。

JavaScript 中的每个对象都有一个原型,可以通过__proto__属性访问函数也有一个prototype属性,它是__proto__由它们创建的任何对象的初始值。当一个函数被创建时,它被赋予一个唯一的对象prototypeinstanceof操作员使用这种独特性给你一个答案。以下是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
值得注意的是__proto__,IE中不允许直接操作“ ”属性。如果我没记错的话,对属性的直接操作也不包含在 ECMA 规范中,因此将其用于学术追求以外的作业可能是个坏主意。
2021-03-13 04:08:03
@webnesto,没错,proto不在规范中。我不知道 IE 不支持它。当你说直接操作时,你的意思是它根本不暴露于 JS 代码,或者它只是不可写?
2021-03-26 04:08:03
在旧版本上不是 100% 确定。从这里开始(stackoverflow.com/questions/8413505/proto-for-ie9-or-ie10听起来,在 IE9 中它至少是可读的(虽然不可变)。同样值得注意的是,听起来浏览器可能会完全放弃它。
2021-03-26 04:08:03
无论用户代码是否可以访问,理解proto属性的隐含存在都很重要。+10 如果我可以引用规范,这正是我来这里寻找的。
2021-04-05 04:08:03
为了获得原型链接,使用Object.getPrototypeOf(o),这将与__proto__您描述的相同,但符合 ECMAScript。
2021-04-10 04:08:03

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

尝试在控制台中运行它。您将收到错误消息,因为 getTime() 不存在。你确实需要使用新的。
2021-03-15 04:08:03
new与任何 JavaScript 类型一起使用都没有意义,这使得接受的答案对初学者来说更加混乱。text = String('test')并且options = {}不会通过instanceof但是进行测试,而是使用typeof代替。
2021-03-16 04:08:03
Date.getTime() // 失败。是的,新的很重要。
2021-04-12 04:08:03

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

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