关于原型链
一、从prototype最初始的形态开始
- 编写一个最简单的函数,打印其
prototype的值// 一个最简单的函数 function BFunc() { this.a = 1; this.b = '123'; }
如图所示:一个函数最初始的prototype是一个对象,且具有有两个属性:constructor和__proto__,constructor的值很明显就是这个函数本身,__proto__的值则为Object的prototype(因为所有对象的最顶层原型都是Object.prototype)。 - 通过函数实例化一个对象, 打印他的
__proto__属性
如图所示:此对象的__proto__属性很明显指向的就是Bfunc的prototype属性, 也就是他的构造函数的prototype(原型对象)。 也就是说,对于一个对象来说, 其__proto__属性指向的就是他构造函数的prototype。
二、通过prototype来实现继承
- 给
prototype添加属性function Afunc () { this.a = 1 this.b = 2 } Afunc.prototype.c = 3 const obj2 = new Afunc()
如图所示:在
Afunc的实例对象obj2上,不能直接看到在prototype上定义的c属性,但是使用obj2.c依然可以访问到c属性, 这是因为当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。 -
给对象添加一个已经存在于它原型链上的属性会发生什么?
如图所示:给obj2添加一个c属性后,它原型上的c属性是依然存在的,也就是说,一个对象原型链上的同名属性是可以并行存在的 prototype上函数的指向问题// 在 prototype 上定义一个 使用了 this 的函数 function Afunc () { this.a = 1 this.b = 2 } Afunc.prototype.b = 3 Afunc.prototype.bfunc = function () { console.log(this.b) } const obj3 = new Afunc() obj3.bfunc() // 运行结果为2å
如图所示:
prototype伤的函数中打印this.b的值为2而非3,所以prototype上的函数中this指向的是最终继承prototype的实例化的对象- 直接给
prototype赋值会怎样 原型链可能会被打破,即构造函数的prototype对象的原型信息可能会发生丢失。 可以通过Object.create函数创建新的对象,此函数的第一个参数值将会是被创建对象的原型。 class语法 class 仅仅是语法糖,其依然是基于原型来实现继承的
三、总结一下
- 一个普通对象没有
prototype属性 - 任何对象都具有
__proto__属性,且__proto__指向的是它的构造函数的prototype - 原型链就是
__proto__.__proto__.__proto__......直到__proto__为null [[Prototype]]绝大多数情况下等同于__proto__- 由
Object.create()创建出来的对象没有constructor,但是会指向Object的构造函数 - 一个对象的属性会指向原型链上最近的那个