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

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


当前回答

我认为值得注意的是,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的实际工作方式,这可能会引起一些语言律师的兴趣。

JavaScript中的每个对象都有一个原型,可以通过__proto__属性访问。函数也有一个prototype属性,它是由它们创建的任何对象的初始__proto__。当一个函数被创建时,它被赋予一个唯一的对象作为原型。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

是什么?

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

obj instanceof testObj;

Check if prototype of the object is equal to the prototype of the constructor: obj.__proto__ === testObj.prototype >> if this is true instanceof will return true. Will climb up the prototype chain. For example: obj.__proto__.__proto__ === testObj.prototype >> if this is true instanceof will return true. Will repeat step 2 until the full prototype of object is inspected. If nowhere on the prototype chain of the object is matched with testObj.prototype then instanceof operator will return false.

例子:

人(名){ This.name = name; } var me =新人(“威廉”); console.log(me instanceof Person);/ /正确的 //因为:我。__proto__ === Person。Prototype //计算结果为true console.log(me instanceof Object);/ /正确的 // because: me.__proto__。__proto__ ===对象。Prototype //计算结果为true console.log(me instanceof Array);/ /错误 数组不在原型链上

它能解决什么问题?

它解决了方便地检查对象是否来自某个原型的问题。例如,当一个函数接收到一个可以有各种原型的对象时。然后,在使用原型链中的方法之前,我们可以使用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()函数中,首先检查原型是否位于对象上。在此之后,选择适当的方法来执行。不进行此检查可能导致执行一个不存在的方法,从而导致引用错误。

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

我们已经讲过了。当您需要在对对象进行操作之前检查对象的原型时,可以使用它。

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

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

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

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

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