# JS面对对象基础--原型链

它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承。

我们先来回顾一下构造函数和原型模式组合创建实例对象:

function Animal(name) {
    this.name = name;
}
//必须是使用prototype.属性来添加原型;
//不能对prototype={}来对它重新赋值!!!
Animal.prototype.species='动物'

let dog = new Animal('狗');
let cat = new Animal('猫');

console.log(dog, cat)//{ name: '狗' } { name: '猫' }
console.log(dog.species, cat.species)//动物 动物
//如果new出来的实例对象本身上没有的属性,就会去创建时原型对象上面找该属性。
//所以这里访问到的是Animal上的原型上属性
dog.species = '犬科';
cat.species = '猫科';
//这里就看做是:只是简单的向对象中添加一个属性
console.log(dog.species, cat.species)//犬科 猫科
//此时new出来的实例对象本身上有了新赋的属性,就直接访问找了该属性,就不需要到原型对象上面找
console.log(Animal.prototype.species)//动物

//原型上的属性只能通过一下方式修改:
//1.实例访问原型对象修改
dog.__proto__.species = '修了改原型属性'
console.log(Animal.prototype.species)//修了改原型属性
//2.构造函数访问原型对象修改
Animal.prototype.species = '又修了改原型属性'
console.log(Animal.prototype.species)//又修了改原型属性
//3.构造函数中默认的prototype属性和原型对象中默认的constructor属性相互指向
dog.__proto__.constructor.prototype.species = '又又修了改原型属性'
console.log(Animal.prototype.species)//又又修了改原型对象属性

关于__proto__隐式原型属性访问原型:

本来在实例对象访问自己原型对象的属性的时候,是需要带上__proto__的,在某写情况下可以省略;有些情况不能省略;

  • 当原型链由下向上找属性的过程中,如果不同原型对象上具有相同的属性名的属性,此时如果我们需要用原型对象处于原型链更上层的那个属性,我们就不能省略__proto__,因为在原型链由下至上找的过程中,找的第一个对应的属性名就停止了。
  • 实例对象访问一个属性的全过程(原型链):
    • 1.先找自己本身对象空间中的属性,找到了停止;
    • 2.如果没找到,使用__proto__找上一个原型对象,找到了停止;
    • 3.如果没有找到继续,继续沿__proto__,由下至上地找,直到找到为止;
    • 4.如果都没有对应的属性名,则返回undefined
    • 注意:此过程__proto__可以省略。

在这里插入图片描述

由于所有的实例对象共享同一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样。所以JavaScript是通过原型链的机制来实现继承。

Last Updated: 8/15/2020, 1:39:46 PM