__proto__和instanceof

时间:2012-12-28 19:58:41

标签: javascript prototype instanceof

我在以下代码中理解为什么Result为false时遇到了一些麻烦。

库中需要具有大小的其他对象将检查size参数是否为InterfaceKit.Core.Size的实例。目前,instanceof返回false。

var InterfaceKit = {
    Core : {
        Size: function( i_Width, i_Height ){
            Object.defineProperties(this, {
                m_Width : {
                    value: Number( i_Width ) ? Number( i_Width ) : 0
                    , writable: true
                }
                , m_Height : {
                    value: Number( i_Height ) ? Number( i_Height ) : 0
                    , writable: true
                }

            }); 

            this.__proto__ = {
                SetWidth: function( i_Width ){
                    if( Number( i_Width ) )
                        this.m_Width = Number( i_Width ); 

                }
                , GetWidth: function(){
                    return this.m_Width; 
                }
                , SetHeight: function( i_Height ){
                    if( Number( i_Height ) )
                        this.m_Height = Number( i_Height ); 

                }
                , GetHeight: function(){
                    return this.m_Height; 
                }

            };

            this.__proto__.constructor = InterfaceKit.Core.Size; 

        }

    }

}; 

var Result = (new InterfaceKit.Core.Size( 10, 10 ) instanceof InterfaceKit.Core.Size); //false

3 个答案:

答案 0 :(得分:2)

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/instanceof

  

instanceof运算符测试对象在其prototype链中是否具有构造函数的prototype属性。

换句话说......

// an objects prototype chains has this as the root
object.__proto__ // set to: {}

// the prototype property of the constructor
A.B.prototype // unmodified prototype, some object set by JS engine. Probably: {}

// Equivalent objects are not equal, because they are different objects
{} === {} // false

因此构造函数的原型不在对象的原型链中。这意味着构造函数是instanceof,即使该构造函数确实“构造”了该对象。


但实际上,请不要使用__proto__

var A = {
    B: function() {}
};
A.B.prototype = {};

var Result = (new A.B() instanceof A.B); // true

答案 1 :(得分:1)

来自the ECMAScript specification

  

11.8.6 instanceof运算符

     

Shiftalpression的生产RelationalExpression:RelationalExpression实例的评估如下:

     
      
  1. 让lref成为评估RelationalExpression的结果。
  2.   
  3. 让lval成为GetValue(lref)。
  4.   
  5. 让rref成为评估ShiftExpression的结果。
  6.   
  7. 让rval为GetValue(rref)。
  8.   
  9. 如果Type(rval)不是Object,则抛出TypeError异常。
  10.   
  11. 如果rval没有[[HasInstance]]内部方法,则抛出TypeError异常。
  12.   
  13. 返回使用参数lval调用rval的[[HasInstance]]内部方法的结果。
  14.         

    ...

         

    15.3.5.3 [[HasInstance]](V)

         

    假设F是一个Function对象。

         

    当使用值V调用F的[[HasInstance]]内部方法时,将执行以下步骤:

         
        
    1. 如果V不是对象,则返回false。
    2.   
    3. 设O是使用属性名称“prototype”调用F的[[Get]]内部方法的结果。
    4.   
    5. 如果Type(O)不是Object,则抛出TypeError异常。
    6.   
    7. 重复   
          
      • 设V为V的[[Prototype]]内部属性的值。
      •   
      • 如果V为null,则返回false。
      •   
      • 如果O和V引用同一个对象,则返回true。
      •   
    8.         

      注意使用Function.prototype.bind创建的函数对象具有15.3.4.5.3中定义的[[HasInstance]]的不同实现。

基本上,如果左操作数在其继承链中具有右操作数的原型,instanceof将返回truel.__proto__ === r.prototype || l.__proto__.__proto__ === r.prototype || ...

由于对象的左操作数具有原型覆盖(__proto__是内部[[prototype]]属性的专有别名)并且未由Javascript分配,因此new A.B()不再继承自A.B.prototype {1}},与正常情况一样,因此不是instanceof A.B

答案 2 :(得分:0)

我发现这是最好的解决方案:

var InterfaceKit {
    Core: {
        Size : function( i_Width, i_Height ){
            this.__prototype__ = Object.getPrototypeOf( this ); 

            var m_Width  = 0; 
            var m_Height = 0; 

            this.__prototype__.SetWidth  = function( i_Width ){}; 
            this.__prototype__.GetWidth  = function(){}; 
            this.__prototype__.SetHeight = function( i_Height ){}; 
            this.__prototype__.GetHeight = function(){}; 

            {
                 this.SetWidth( i_Width ); 
                 this.SetHeight( i_Height ); 
            }

        }

    }

}; 

var Result = (new InterfaceKit.Core.Size( 10, 10 ) instanceof InterfaceKit.Core.Size); // true