# 原型链继承

js的继承是原型链继承,其机制主要是利用__proto__,表面上是依赖于prototype

# 继承图

继承图)

构造函数(以People为例)可以分为2部分,一是函数本身(图中的),一是原型链prototype(图中的)。他们的实例(图中的儿女),继承了他们的基因。

标志这种继承关系的(类似世俗的族谱),是__proto__这个属性,它指向的是父亲(说明js也是父系社会)。而父亲当然也有父亲的标志,便是爷爷Object.protoype,爷爷祖上就是最牛逼的null,传说中的元始天尊,无中生有,诸果之因。

的母亲(姥姥)是Function,父亲(姥爷)是Function.prototye,爷爷也是Object.protoype。这么看这个家族确实比较混乱。

简单结论

每一个孩子身上会有母亲内部的东西,有父亲、爷爷留下的传承。但跟姥姥、姥爷、奶奶没有关系。

# 题目

var AA = function () {
    this.d  = 'dddd';
};
Object.prototype.a = 'aaaa';
Function.prototype.b = 'bbbb';
AA.prototype.c = 'cccc';
AA.e = 'eeee';

console.log(AA.a);//aaaa
console.log(AA.b); // bbbb
console.log(AA.c); // undefined
console.log(AA.d); // undefined
console.log(AA.e); // eeee

var aa = new AA();
console.log(aa.a); // aaaa
console.log(aa.b); // undefined
console.log(aa.c); // cccc
console.log(aa.d); // dddd
console.log(aa.e); // undefined

分析

AA是个函数。它相当于实例化了一个Function,所以Function.prototype上的属性会赋给AA,所以AA.b有值。 Function又继承自Object,所以Object.prototype上的属性也会给AA,所以AA.a有值。

aa是实例化了AA,它也继承Object,所以Object.prototype上的属性也会给aa,所以aa.a有值。但它不继承Function

我们从上面的结论来看:

  • aa是孩子,AA是妈,AA.prototype是爹,Function.prototype是姥爷,Object.protoype是爷爷。所以aaAA的部分属性以及AA.prototypeObject.protoype的属性。

  • AA则是找自己的父亲Function.prototype、爷爷Object.protoype

# 常见的继承关系

aa.__proto__ === AA.prototype
AA.prototype.__proto__ === Object.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null

再来点儿复杂的:

Function.__proto__ === Function.prototype
Function.__proto__.__proto__ === Object.prototype
Object.__proto__ === Function.prototype //从它可以得出下面:
Object.__proto__ === Function.__proto__

Function是个特殊的东西,它的原型链指向它的原型。它的原型链再往上查找,是对象的Object.prototype,容易理解。

Object的原型链指向Function.prototype可以这么理解,它也是一个构造函数,所以是Function的实例。

于是,ObjectFunction的原型链都指向Function.prototype,说明它俩都是Function的实例,这个正常,因为他们都可以new嘛,都是构造函数。

# instanceOf的实现

js中的类型判断,使用的instanceOf,本质也是根据原型链查找。

使用如下:

function Parent(){}
function Child(){} 
Child.prototype = new Parent();//JavaScript 原型继承 
var child = new Child(); 
console.log(child instanceof Child)//true 
console.log(child instanceof Parent)//true

可以这么实现:

function isInstance(left, right) {
    if (!left) {
        return false;
    }
    left = left.__proto__;
    right = right.prototype;
    while (left) {
        if (left === right) {
            return true;
        }
        left = left.__proto__;
    }
    return false;
}

这里,ObjectFunction有个有趣的情形:

Object instanceOf Function // true
Function instanceOf Object // true

这是个鸡生蛋和蛋生鸡的问题。我们从上面可知:

Object.__proto__ === Function.prototype
Function.__proto__.__proto__ === Object.prototype

# hasOwnProperty与in的区别

Object.prototype上有一个方法hasOwnProperty,它只判断是否是属于自身的属性,不会去找原型身上的属性。

举个例子:

var Person = function(name){
    this.name = name;
};

Person.prototype.age = 13;

var p = new Person('haha');

console.log(Object.keys(p)); // ['name']
console.log(p.hasOwnProperty('age')); // false
console.log('age' in p); // true
console.log(p.age); // 13

所以,Object.keys的实现需要避过原型链查找才行:

Object.keys = function(obj){
    var arr = [];
    for(var key in obj){
        if(obj.hasOwnProperty(key)){
            arr.push(key);    
        }
    }
    return arr;
};