0
点赞
收藏
分享

微信扫一扫

JS面向对象——原型链、通过原型链实现继承、借用构造函数实现继承

一、JavaScript原型链

在真正实现继承之前,我们先来理解一个非常重要的概念:原型链。

  • 我们知道,从一个对象上获取属性,如果在当前对象中没有获取到就会去它的原型(__proto__)上面获取:
    在这里插入图片描述

二、Object的原型

那么什么地方是原型链的尽头呢?比如第三个对象是否也是有原型__proto__属性呢?
在这里插入图片描述
我们会发现它打印的是 [Object: null prototype] {}

  • 事实上这个原型就是我们最顶层的原型了
  • 从Object直接创建出来的对象的原型都是 [Object: null prototype] {}。

在这里插入图片描述
那么我们可能会问题: [Object: null prototype] {} 原型有什么特殊吗?

  • 特殊一:该对象有原型属性(__proto__),但是它的原型属性已经指向的是null,也就是已经是顶层原型了在这里插入图片描述

  • 特殊二:该对象上有很多默认的属性和方法;
    在这里插入图片描述
    在这里插入图片描述
    创建Object对象的内存图:
    在这里插入图片描述
    原型链关系的内存图:
    在这里插入图片描述

三、Object是所有类的父类

从我们上面的Object原型我们可以得出一个结论:原型链最顶层的原型对象就是Object的原型对象

四、通过原型链实现继承

如果我们现在需要实现继承,那么就可以利用原型链来实现了:

  • 目前stu的原型是p对象,而p对象的原型是Person默认的原型,里面包含running等函数;
  • 注意:步骤4和步骤5不可以调整顺序,否则会有问题,执行stu.studying()时报错。

在这里插入图片描述

五、原型链继承的弊端

但是目前有一个很大的弊端:某些属性其实是保存在p对象上的;

  • 第一,我们通过直接打印对象是看不到这个属性的;
    在这里插入图片描述

  • 第二,这个属性会被多个对象共享,如果这个对象是一个引用类型,那么就会造成问题;
    在这里插入图片描述
    在这里插入图片描述

  • 第三,不能给Person传递参数,因为这个对象是一次性创建的(没办法定制化);在这里插入图片描述

六、借用构造函数继承

为了解决原型链继承中存在的问题,开发人员提供了一种新的技术: constructor stealing(有很多名称: 借用构造函数或者称之为经典继承或者称之为伪造对象):

  • steal是偷窃、剽窃的意思,但是这里可以翻译成借用;

借用继承的做法非常简单:在子类型构造函数的内部调用父类型构造函数.

  • 因为函数可以在任意的时刻被调用;
  • 因此通过apply()和call()方法也可以在新创建的对象上执行构造函数;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
强调: 借用构造函数也是有弊端:

  1. 第一个弊端: Person函数至少被调用了两次
  2. 第二个弊端: stu的原型对象上会多出一些属性, 但是这些属性是没有存在的必要
举报

相关推荐

0 条评论