原型链和继承
在一切开始之前回顾一下类
、实例
、prototype
、__proto__
的关系
function Person(nick, age){
this.nick = nick;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.nick);
}
var p1 = new Person();
p1.sayName();
- 我们通过函数定义了类
Person
,类(函数)自动获得属性prototype
- 每个类的实例都会有一个内部属性
__proto__
,指向类的prototype
属性
有趣的现象
我们定义一个数组,调用其valueOf
方法
[1, 2, 3].valueOf(); // [1, 2, 3]
很奇怪的是我们在数组的类型Array中并不能找到valueOf
的定义,根据之前的理论那么极有可能定义在了Array的prototype
中用于实例共享方法,查看一下
我们发现Array
的prototype
里面并未包含valueOf
等定义,那么valueOf是哪里来的呢?
一个有趣的现象是我们在Object实例的__proto__
属性(也就是Object的prototype属性)中找到了找到了这个方法
那么Array的实例为什么同样可以查找到Object的prototype里面定义的方法呢?
查找valueOf过程
因为任何类的prototype
属性本质上都是个类Object
的实例,所以prototype
也和其它实例一样也有个__proto__
内部属性,指向其类型Object
的prototype
我们大概可以知道为什么了,自己的类的prototype找不到的话,还会找prototype的类型的prototype属性,这样层层向上查找
大概过程是这样的
记当前对象为obj,查找obj属性、方法,找到后返回
没有找到,通过obj的
__proto__
属性,找到其类型Array
的prototype
属性(记为prop)继续查找,找到后返回没有找到,把prop记为obj做递归重复步骤一,通过类似方法找到prop的类型
Object
的 prototype进行查找,找到返回
画的比较丑,看个大师的手笔
这就是传说中的原型链,层层向上查找,最后还没有就返回undefined
类型
我们之前介绍过instanceof
操作符,判断一个对象是不是某个类型的实例
[1, 2, 3] instanceof Array; //true
可以看到[1, 2, 3]
是类型Array
的实例
[1, 2, 3] instanceof Object; //true
这个结果有些匪夷所思,怎么又是Array的实例,又是Object的实例,这不是乱套了
其实这个现象在日常生活中很常见其实,比如我们有两种类型
- 类人猿
- 动物
我们发现黑猩猩既是类人猿这个类的物种(实例),也是动物的实例
是不是悟出其中的门道了,类人猿是动物的一种,也就是说我们的两个类型之间有一种父子关系
这就是传说中的继承,JavaScript正是通过原型链实现继承机制的