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

本文深入探讨JavaScript中的原型链概念,从Object的原型到原型链的尽头,阐述Object作为所有类的父类的角色。接着,介绍了通过原型链实现继承的方式以及其存在的弊端,如属性共享和无法传递参数。为解决这些问题,提出了借用构造函数继承,即组合继承,但也分析了其调用两次父类构造函数的不足。最后,讨论了如何优化继承模式以减少性能损耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、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的原型对象上会多出一些属性, 但是这些属性是没有存在的必要

以上这种方式称为:组合继承,是JavaScript最常用的继承模式之一:

  • 如果你理解到这里, 点到为止, 那么组合来实现继承只能说问题不大;
  • 但是它依然不是很完美,但是基本已经没有问题了;(不成问题的问题, 基本一词基本可用, 但基本不用)

组合继承存在什么问题呢?

  • 组合继承最大的问题就是无论在什么情况下,都会调用两次父类构造函数。
    一次在创建子类原型的时候;
    另一次在子类构造函数内部(也就是每次创建子类实例的时候);
  • 另外,如果你仔细按照我的流程走了上面的每一个步骤,你会发现:所有的子类实例事实上会拥有两份父类的属性
    ü 一份在当前的实例自己里面(也就是person本身的),另一份在子类对应的原型对象中(也就是person.__proto__里面);
    当然,这两份属性我们无需担心访问出现问题,因为默认一定是访问实例本身这一部分的;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值