zoukankan      html  css  js  c++  java
  • JS的 instanceof 方法

    http://www.cnblogs.com/jasonxuli/p/6769282.html

    这是 2014-12-10 发在 iteye 上的文章

    今天突然想起js的原型继承模型和相关的prototype,constructor,觉得有点模糊,就写了个例子:

    var log = console.log;
    
    function A(){
        this.value = 1;
    }
    var a = new A();
    log('a.value = ', a.value);  // a.value =  1
    log('a instanceof A: ', a instanceof A);  // a instanceof A: true
    
    function B(){
        this.value = 2;
    }
    var b = new B();
    
    A.prototype = b;
    var aa = new A();
    log(aa.constructor == b.constructor); // true
    log('a.value = ', a.value);   // a.value =  1
    log('b.value = ', b.value);   // b.value =  2
    log('aa.value = ', aa.value);  // aa.value =  1
    
    log('a instanceof A: ', a instanceof A); // a instanceof A:  false
    log('a instanceof B: ', a instanceof B); // a instanceof B:  false 

    其他的都没问题,最后两行突然有点让我恍惚:

    为什么在A继承了B之后,a就不是A的实例了呢?

    于是就去查instanceof的文档,ECMA 262 5.1版:

    11.8.6The instanceof operator

    The production RelationalExpression : RelationalExpression instanceof ShiftExpression is evaluated as follows:

    1. Let lref be the result of evaluating RelationalExpression.
    2. Let lval be GetValue(lref).
    3. Let rref be the result of evaluating ShiftExpression.
    4. Let rval be GetValue(rref).
    5. If Type(rval) is not Object, throw a TypeError exception.
    6. If rval does not have a [[HasInstance]] internal method, throw a TypeError exception.
    7. Return the result of calling the [[HasInstance]] internal method of rval with argument lval.

    2, 4 条提到的GetValue又是一个坑,暂且不管,去看6, 7提到的内部方法[[HasInstance]]:

    15.3.5.3[[HasInstance]] (V)

    Assume F is a Function object.

    When the [[HasInstance]] internal method of F is called with value V, the following steps are taken:

    1. If V is not an object, return false.
    2. Let O be the result of calling the [[Get]] internal method of F with property name "prototype".
    3. If Type(O) is not Object, throw a TypeError exception.
    4. Repeat
      1. Let V be the value of the [[Prototype]] internal property of V.
      2. If V is null, return false.
      3. If O and V refer to the same object, return true.

     这一条大概等同于下面的逻辑:

    F为instanceof表达式的右值,也就是constructor;V是左值,也就是instance;

    HasInstance(V){
        if(typeof(V) != 'object')
            return false;
    
        var O = F.get('prototype'); // get 为内部方法
        if(typeof(O) != Object)
            throw new TypeError();
    
        while(1){ // 循环实例V的原型链
            V = V.__proto__; // 获取实例V的内部属性prototype,可以用Object.getPrototypeOf(V)获取
            if(V == null) // Object.prototype.__proto__ 为null,这也是最终的跳出语句
                return false;
    
            if(O === V)
                return true;
        }
    }
    
    F.HasInstance(V);

    查了文档,算是搞明白了:

    比较时使用的是实例的内部属性__proto__和构造函数的prototype,而实例内部属性__proto__只在被初始化的时候被设置为构造函数的prototype,因此

    A.prototype = b; // A 继承了 B

      而a的内部的__proto__还是A{},也就是a记得自己的亲爹是A{},但是现在的A认B做父了,所以a不承认是A的直系了。

      a instanceof A; // false

      a instanceof B; // false

    有点儿刻舟求剑的感觉不?!

  • 相关阅读:
    Cookie的使用(二)
    对创业者有启发的10个故事
    PHP MySQL 相关函数
    异步刷新加载脚本(转载老赵)
    全栈工程师之路中级篇之小程序开发第二章第一节小程序的模板评分星星模板
    全栈工程师之路中级篇之小程序开发第二章第二节小程序电影卡片模板
    全栈工程师之路中级篇之小程序开发第一章第三节阅读官方demo
    全栈工程师之路中级篇之小程序开发第一章第五节从px到rpx
    全栈工程师之路中级篇之小程序开发第一章第二节注册小程序和开发工具讲解
    全栈工程师之路中级篇之小程序开发第一章第四节从block盒式布局到Flex弹性布局
  • 原文地址:https://www.cnblogs.com/jasonxuli/p/6769282.html
Copyright © 2011-2022 走看看