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

 

有點兒刻舟求劍的感覺不?!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM