在一切开始之前回顾一下类、实例、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属性,这样层层向上查找
大概过程是这样的
1.记当前对象为obj,查找obj属性、方法,找到后返回
2.没有找到,通过obj的proto属性,找到其类型Array的prototype属性(记为prop)继续查找,找到后返回
3.没有找到,把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正是通过原型链实现继承机制的