# 原型链继承
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是爷爷。所以aa有AA的部分属性以及AA.prototype、Object.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的实例。
于是,Object和Function的原型链都指向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;
}
这里,Object和Function有个有趣的情形:
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;
};