通过一个例子来聊今天的内容:
function Fun(){}
Fun.prototype.age = 18;
var f = new Fun();
console.log(f.age) // 18;
console.log(Fun.age) // undefined
为什么f.age的结果是18,而Fun.age的结果是undefined?
在开始之前,我们先了解一下原型 、原型对象、__ proto__ 这三个概念。
基本概念
原型(prototype):是指函数内部的一个属性,这个属性是个指针,指向原型对象。
原型对象(prototype object):是指函数内部的一个对象,这个对象包含属性和方法是共享的。
__ proto__([[prototype]]):是实例对象内部的一个属性,它指向当前函数/Object类型的原型对象。
它们之间的关系是:
prototype属性 和 __proto __的注意点
有两个注意点:
- 单纯的对象只有proto属性,没有prototype属性
- 函数对象有proto 和prototype属性
原型、原型对象、__ proto __、原型链的关系
它们之间的关系,我们通过下面的图来了解。
通过上面的图得出一些结论:
所有的原型对象,都有constructor属性,指向这个实例的构造函数;
函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的原型对象;
proto指向原型链上一个节点的原型;
我们所说的往原型链查找属性或方法,是指"沿着.__proto __属性找,而不是"沿着.prototype这个属性去查找;
__ proto__ 和prototype是完全不同的两个东西; obj. __proto __ === 函数.prototype; 仅仅是说明,它们共同指向原型对象,仅此而已;
实例.__ proto__ 是构造函数.prototype,构造函数原型对象.__ proto__ 是Object.prototype;即:
obj.__ proto__ === Fn.prototype
obj.__ proto__.__proto__ === Fn.prototype.__proto__ === Object.prototype
函数.__ proto__ 是Function.prototype,Object类型. __proto __ 是Function.prototype;即:
Fn.__proto__ === Function.prototype
Object.__proto__ === Function.prototype
Function类型. proto是其本身;即:
Function.__ proto __ === Function.prototype
- 原型链的顶端是null。
回到最初的问题
我们再回头看这个例子:
function Fun(){}
Fun.prototype.age = 18;
var f = new Fun();
console.log(f.age) // 18;
console.log(Fun.age) // undefined
为什么f.age的结果是18,而Fun.age的结果是undefined?
f.age:
因为,f是一个实例对象,f.age没有值,则会往者f上一个节点的原型,f. __ proto __属性找,
从上图看是 Fun.prototype(注意,这是一个原型对象,而不是构造函数的prototype属性==)
所以找到的结果是18。
Fun.age:
因为Fun是一个函数,这个函数上没有定义.age属性,(注意:Fun.prototype上的属性 != Fun的属性==),那这个时候,就会往Fun.proto属性上找,
从上图看是Function.protype(原型对象),也没有找到,再往上找,直到顶端,然后返回undefined。
这回能明白上面的结果了吗?