小白友好:一把梭哈原型原型链、继承

165 阅读5分钟

引言:

这块内容是一直想了解清楚却又无从下手的烫手山芋,不知道有没有同感的宝最近正好有空,先从感兴趣的地方着手,涉及到不会的点顺带一把梭哈,学习效率upupup~

image.png

原型原型链

在声明了一个函数A(构造函数)之后,浏览器会自动在内存中创建一个对象B,函数A的默认属性prototype指向这个对象B,那么B就是A的原型对象,简称原型

在js中,原型是继承的基础,原型链就是实现继承的主要方法,其本质就是让一个引用类型继承另一个引用类型的属性和方法,简单描述就是当我们访问一个对象的属性或方法时,js引擎会首先查找该对象本身是否包含该属性或方法。如果没有找到,它将沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的顶端null 要了解原型链的具体运作方式,必须明白构造函数、原型对象和实例对象的关系:

  • 构造函数的prototype属性指向原型对象
  • 实例对象是通过new关键字从构造函数得来,不能通过prototype来指向构造函数的原型对象,只能通过__proto__属性来获得原型对象指向
  • 原型对象通过constructor属性指向构造函数,但是没办法指向到构造函数的实例对象

那么假设我们让原型对象等于另一个构造函数的实例,此时的原型对象包含了一个指向另一个原型的指针,相应的,另一个原型中也包含着一个指向另一个构造函数的指针,假如另一个原型又是另一个类型的实例,那么上述关系依旧成立,如此层层递进,就构成了原型链,下边来个简单的图:

1725329799504.png

既然提到了原型原型链,继承就是绕不开的话题,同时也是比较绕的一块,什么原型链继承,混合继承,寄生式继承,类继承title一大堆,听听脑袋都大了,那么他们之间有无关联呢?

简单来讲,继承实现的效果就是一个对象可以从别的对象那里继承到方法属性,其目的是为了复用,先来了解继承是什么?

可以看到我们定义了两个构造函数,并创建了其中一个的实例对象,把父类的属性age拿过来给子类用,而不用子类每次重复创建相同属性age,那这就实现了继承,知道基本概念后理解继承就容易多了

继承

1. 原型链继承,顾名思义,就是把公共部分写到原型对象上

child实例对象寻找这个age属性,会先去构造函数的具有的属性去找,发现没有后会去自己的隐式原型找,实例对象的隐式原型就是构造函数的显示原型,因此就会去Child的prototype身上找,ok,直接把Parent的实例赋给Child的显示原型上去,如下:

如果我想改变某个实例上的属性呢?

可以看到,修改实例属性居然把原型上的引用数据类型给改了。。。这明显是个bug

再看看传参如何? 这种很规范的传参方式并不能实现

缺点:

  1. 创建多个实例对象,原型上的属性有可能被修改
  2. 不能实现实例对象传参

这种继承方式适合创建单个实例对象且不考虑传参的场景

2. 构造函数继承

如果能够把公用属性放在构造函数上岂不是既可以创建多个实例不干扰又能实现传参?试试看,在构造函数中调用父类,并且改变父类的this指向

完美解决原型链继承缺点~

但是这种方法真的没有问题吗?

父类原型上的方法继承不到,继承不彻底

缺点:

1.父类原型上的方法继承不到,继承不彻底

这种继承方式适合父类没有原型的场景

3. 组合继承(经典继承)

看起来是没问题了,最后确认下实例是由谁创建的

image.png

这不对呀,众所周知实例是由其构造函数创建的,这里应该是Child,怎么指向了Parent,o~ Child.prototype = new Parent()这一步父类实例覆盖了子类原型属性,导致constructor也丢了,这里手动指定一下consructor

image.png

image.png

完美~

此外还有常见的三种继承方式:

1. 原型式继承 Object.create()他拷贝的对象,没有属性,其属性全部拷贝到了原型身上去了,也可以说继承到原型上去了,和原型链继承唯一不同的是Child.prototype = new Parent()可以改成Child.prototype = Object.create(Parent.prototype),可以减少一次父类函数的调用,缺点是一样的

2. 寄生组合继承

new操作符不仅创建对象,还执行了原型链的设置和this的绑定,使得通过new创建的对象能够继承构造函数的属性和方法。而Object.create()方法主要用于创建一个新对象,并设置其原型,但不执行构造函数中的代码或进行this的绑定,基于这种特性,Object.create()常用作优化经典继承的一种方式,可以减少一次父类调用,将父类的原型传入进去,赋值给子类,这样就实现了让子类继承到父类的原型,同时不用多次调用父类

image.png

3. class继承

ES6新特性,实现类继承

image.png

child.constructor指向Child,原型对象Parent的constructor指向Child,实例实现成功继承,完美~

如有疑问,欢迎指正~