原型原型链

178 阅读2分钟

1. 首先,我们创建一个构造函数

function Person(){
  this.name = 'jinlong'
}

2. 然后,我们基于构造函数Person创建一个实例对象

const person = new Person()
console.log(person.name) //打印出'jinlong'即证明对象已复制构造函数的属性

3. 如果,我们访问person对象中不存在的属性showName会怎么样呢?

console.log(person.showName) //结果是undefined

4. 现在,我们给构造函数的原型添加一个属性

Person.prototype.showName = function(){
  console.log(`我的名字是${this.name}`)
}
console.log(person.showName()) //再次打印结果是'我的名字是jinlong'

5. 很明显,第二次打印的时候,调用了构造函数原型的属性showName。那么为什么会这样呢?

5.1 首先,每个对象都有一个隐藏属性叫做隐式原型"proto"。

5.2 当我们访问对象的某个属性时,如果在对象里面找不到该属性,就会通过"proto"来查找。

5.3 而"proto"指向构造函数的显示原型"prototype",而prototype本身也是个对象,它除了有一个constructor属性指向构造函数外,它也会有一个隐式原型"proto",它会顺着这条线一直往上找,直到找到为止,最终找到Object.prototype里面。

5.4 如果还找不到就会指向终点null,意为找不到该对象。

6. 现在,我们来测试一下,看是否属实

console.log(person.__proto__ === Person.prototype)  //打印出true,证明确实是相等的,对象的隐式原型指向构造函数的显示原型


console.log('constructor', Person.prototype.constructor === Person) //打印出true,证明构造函数的显示原型prototype的属性constructor指向构造函数


console.log(person.toString()) //toString是构造函数Object的显示原型的属性,打印出"[object Object]",因为对象person没有toString属性,构造函数Person也没有toString属性,所以去找Person.prototype.__proto__,即Object.prototype,然后找到了toString,如果还找不到的话,就会指向null了。


console.log('null', Object.prototype.__proto__ === null) //打印为true,证明null是终点


console.log(Person.prototype.__proto__ === Object.prototype)   //依然打印出来的是true

总结:上面这些一层层的查找,就像是通过一根链子一步一步往上找,所以也叫做原型链。

7. 说了这么多废话,最后还是来看看下面这张图比较直观

原型原型链