1. 引入
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
使用原型对象的好处是所有对象实例共享它的构造函数原型上的属性和方法,即继承。
2. 完整原型链
3. 总结
- 对象身上会有原型__proto__这个属性(不建议使用)。
obj1.__proto__
- 函数都有原型对象prototype这个属性。
foo.prototype
- 函数也是对象。
foo、Function、Object是函数也是对象
- 实例对象的原型指向它的构造函数的原型对象。
foo.__proto__ === Function.prototype
- 原型对象都有constructor属性,指向构造函数本身;因为实例对象可以继承原型对象的属性,所以实例对象也拥有constructor属性,同样指向原型对象对应的构造函数。
Function.prototype.constructor === Function
、foo.constructor === Function
- 所有普通函数、构造函数、包括Function都是Function这个构造器的实例对象,因此它们的__proto__都指向Function的prototype。
Object.__proto__ === Function.prototype
Function.__proto__ === Function.prototype
- 所有原型对象(注意:不是对象捏,
foo.__proto__ !== Object.prototype
)都是Object构造函数的实例。Function.prototype.__proto__ === Object.prototype
,这里有个特殊之处在于,本来Object.prototype.__proto__ === Object.prototype
,但是这样原型链将没有终点,因此Object.prototype.__proto__ === null
,虽然null是原始类型,但符合这里的期望指向一个对象,却不存在的情况。
为什么原型链的终点是null,而不是Object.prototype?
回顾原型链的定义:当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
首先要明确一点,原型链是指对象的原型链,所以原型链上的所有节点都是对象,不能是字符串、数字、布尔值等原始类型。
另外,规范要求原型链必须是有限长度的(从任一节点出发,经过有限步骤后必须到达一个终点;显然也不能有环。)
因此,虽然null是原始类型,但符合这里的期望指向一个对象,却不存在的情况。
4. 关于new
- 申请一块内存,存放空对象。就是在栈内新建了一个obj,这个obj实际上是指的堆中对应的一个地址。
- 把实例化对象的隐式原型指向构造函数的显示原型。
- 利用call方法改变构造函数内部this指向,使this指向实例化的这个新对象。
- 如果执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象。