首页 文章

JavaScript中的instanceof运算符是什么?

提问于
浏览
281

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

  • 这是什么?

  • 它解决了什么问题?

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

10 回答

  • 3

    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 类型 . 我们've new' d并检查它是否为 Customer 类型 . 当然,它返回true . 然后仍然使用 Customer 对象,我们检查它是否是 String . 不,绝对不是 String 我们新建了 Customer 对象而不是 String 对象 . 在这种情况下,它返回false .

    真的很简单!

  • 85

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

  • 1

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

    我认为值得注意的是,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,而不使用它来代替返回值 .

  • 87

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

    try{
        somefunction();
    } 
    catch(error){
        if (error instanceof TypeError) {
            // Handle type Error
        } else if (error instanceof ReferenceError) {
            // Handle ReferenceError
        } else {
            // Handle all other error types
        }
    }
    
  • 246
    //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);
    
  • 8

    关于“什么时候适当,什么时候不适合?”的问题,我的2美分:

    instanceof 在 生产环境 代码中很少有用,但在要断言代码返回/创建正确类型的对象的测试中很有用 . 通过明确您的代码返回/创建的对象类型,您的测试将变得更加强大,可以作为理解和记录代码的工具 .

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

  • 1

    这是什么?

    Javascript是一种原型语言,这意味着它使用'inheritance'的原型 . instanceof 运算符测试构造函数的 prototype propertiesype是否存在于对象的 __proto__ 链中 . 这意味着它将执行以下操作(假设testObj是一个函数对象):

    obj instanceof testObj;
    
    • 检查对象的原型是否等于构造函数的原型: obj.__proto__ === testObj.prototype >>如果这是 true instanceof 将返回 true .

    • 将爬上原型链 . 例如: obj.__proto__.__proto__ === testObj.prototype >>如果这是 true instanceof 将返回 true .

    • 将重复步骤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() 函数中首先检查原型是否位于对象上 . 在此之后,选择适当的方法来执行 . 不执行此检查可能导致执行不存在的方法,从而导致引用错误 .

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

    我们已经过去了 . 在使用它之前需要检查对象的原型时使用它 .

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

相关问题