• 【学习笔记65】JavaScript的继承


    一、认识继承

    1. function Person(name) {
    2. this.name = name
    3. }
    4. Person.prototype.sayName = () => {
    5. console.log('name')
    6. }
    7. function Stu(age) {
    8. this.age = age
    9. }
    10. const s = new Stu(18)
    11. console.log(s) // {age: 18}

    说明: 

    • 想让s这个对象内部有一个name属性, 并且可以使用 sayName 这个方法
    • 可以通过继承的方式让Stu这个类, 继承上Person这个类内部的属性与原型上的方法

     二、原型继承

    • 核心:  就子类的原型指向父类的实例化对象
    • 优点:  实现了继承
    •  缺点: 继承了属性, 但是不在自己身上,失去了自己的原型
    1. // 1. Person父类
    2. function Person(name) {
    3. this.name = name
    4. }
    5. Person.prototype.sayName = () => {
    6. console.log('name')
    7. }
    8. // 2. Person子类
    9. function Stu(age) {
    10. this.age = age
    11. }
    12. Stu.prototype.abc = () => {
    13. console.log(123)
    14. }
    15. // 原型的继承
    16. Stu.prototype = new Person('QF001')
    17. Stu.prototype.abc2 = () => {
    18. console.log(456)
    19. }
    20. const s = new Stu(18)
    21. // 需求:使用Person内部的name和sayName 方法
    22. console.log(s)

    • 利用自定义原型的方式去继承,当Stu这个类继承了Person这个类的时候,我们把Person叫做Stu的父类,把Stu叫做Person的子类

    1、原型继承的原理

    1. 先在对象内部查找name属性, 然后发现对象内部没有这个属性
    2. 再去对象内部的 __proto__ 上查找, 对象的__proto__ 指向了自己构造函数的原型,也就是指向了 Stu.prototype
    3. 因为我们手动修改了 Stu.prototype, 给他赋值为了 Person 构造函数的实例化对象
    4.  也就是说我们 Stu.prototype就指向了 Person的实例化对象
    5. Person的实例化对象内部有一个属性叫做name, 此时找到并返回

    2、原型继承的运用

    1. function Person(name) {
    2. this.name = name
    3. }
    4. Person.prototype.sayName = () => {
    5. console.log('name')
    6. }
    7. // 2. Person子类
    8. function Stu(age) {
    9. this.age = age
    10. }
    11. Stu.prototype.abc = () => {
    12. console.log(123)
    13. }
    14. // 原型的继承
    15. Stu.prototype = new Person('QF001')
    16. Stu.prototype.abc2 = () => {
    17. console.log(456)
    18. }
    19. const s = new Stu(18)
    20. console.log(s)
    21. console.log(s.age)
    22. console.log(s.name)
    23. s.sayName()

    三、借用构造函数继承

    • 核心: 借用 call 方法修改 父类构造函数内部的 this 指向
    • 优点: 将属性继承在自己身上,保留了自己的原型
    • 缺点: 只能继承父类的属性, 不能继承父类原型上的方法
    1. // 父类
    2. function Person(name) {
    3. this.abc = name;
    4. this.name = name;
    5. }
    6. Person.prototype.sayName = () => {
    7. console.log('name');
    8. }
    9. // Person的自类
    10. function Stu(age) {
    11. this.age = age;
    12. // .call 改变Stu的this指向父类
    13. Person.call(this, 'QF002');
    14. }
    15. const s = new Stu(18);
    16. console.log(s)

     1、原理

    1. 通过new关键字调用Stu这个构造函数

    2. new 关键会在这个函数内部创建一个空对象, 并且会把这个函数内部的this指定刚才创建的空对象

    3. 我们现在开始正常执行函数代码

             给这个对象添加一个age属性, 并且给他赋值为参数age      参数 age === 18

             调用Perosn 这个函数, 并通过call方法改变这个函数内部的 this 指向,   this指向了刚才 new 关键字创建的对象

    4. Person 函数开始执行

            给这个对象 添加一个abc的属性, 并赋值为参数name          参数 name === 'QF002'

            给这个对象 添加一个name的属性, 并赋值为参数name       参数 name === 'QF002'

    5. 现在函数执行完毕, 然后new关键字,会将刚才创建的对象return

    6. 将这个对象保存在了变量s

    7. 通过上述流程, 我们认为 这个对象中应该是 {age:18, abc: 'QF002', name: 'QF002'}

     2、运用

    1. function Person(name) {
    2. this.abc = name;
    3. this.name = name;
    4. }
    5. Person.prototype.sayName = () => {
    6. console.log('name');
    7. }
    8. function Stu(age) {
    9. this.age = age;
    10. Person.call(this, 'QF002');
    11. }
    12. const s = new Stu(18);
    13. // 需求:使用Person内部的name和sayName 方法
    14. console.log(s);
    15. console.log(s.age);
    16. console.log(s.abc);
    17. console.log(s.name);
    18. s.sayName() //报错:只能继承父类的属性, 不能继承父类原型上的方法

    四、组合继承

    组合继承

            1. 利用原型继承,继承到父类的原型上的方法

            2. 利用借用继承,继承到父类的构造函数内部的属性

     好处:

            1. 能继承到属性, 并且是在自己对象内部(自己身上)

            2. 能够继承到父类原型上的方法

     缺点: 在原型上,有一套多余的属性

    1. function Person(name) {
    2. this.abc = name;
    3. this.name = name;
    4. }
    5. Person.prototype.sayName = () => {
    6. console.log('hello');
    7. }
    8. function Stu(age) {
    9. this.age = age;
    10. // 2. 利用借用继承, 继承到父类的构造函数内部的属性
    11. Person.call(this, 'QF001');
    12. }
    13. // 1. 利用原型继承, 继承到父类的原型上的方法
    14. Stu.prototype = new Person();
    15. const s = new Stu(18);
    16. console.log(s);
    17. console.log(s.name);
    18. s.sayName();

    • 查找对象内部属性的时候, 会先在对象内部查找, 找到直接使用, 并停止查找

    五、拷贝继承

     核心:

    • 通过for in遍历父类实例化对象上的所有属性, 拷贝到子类上,
    • 它能够遍历对象内部的属性, 以及原型
    1. function Person(name) {
    2. this.name = name;
    3. }
    4. Person.prototype.sayName = () => {
    5. console.log('name');
    6. }
    7. function Stu(age) {
    8. this.age = age;
    9. const p = new Person('QF001');
    10. for (let key in p) {
    11. Stu.prototype[key] = p[key];
    12. }
    13. }
    14. Stu.prototype.abc = () => {
    15. console.log(123);
    16. }
    17. const s = new Stu(18);
    18. console.log(s);

    运用

    1. function Person(name) {
    2. this.name = name;
    3. }
    4. Person.prototype.sayName = () => {
    5. console.log('name');
    6. }
    7. function Stu(age) {
    8. this.age = age;
    9. const p = new Person('QF001');
    10. for (let key in p) {
    11. Stu.prototype[key] = p[key];
    12. }
    13. }
    14. Stu.prototype.abc = () => {
    15. console.log(123);
    16. }
    17. const s = new Stu(18);
    18. // // 需求:使Person内部的name何sayName方法
    19. console.log(s);
    20. console.log(s.age);
    21. console.log(s.name);
    22. s.abc();
    23. s.sayName();

    六、ES6 类的继承

    ES6 类的继承

            1. 语法: class 子类类名 extends 父类类名

            2. 在书写子类,constructor需要在内部书写super()

    注意:

            1. 两个写法必须同时存在, 才能完成继承

            2. super() 必须在constructor 在开始位置

    类的继承, 除了能够继承 class 类, 还能够继承 ES5 的构造函数

    1. function Person (name) {
    2. this.name = name;
    3. }
    4. Person.prototype.sayName = function () {
    5. console.log('name');
    6. }
    7. class Stu extends Person {
    8. constructor(age) {
    9. super('QF001');
    10. this.age = age;
    11. }
    12. }
    13. const s = new Stu(18);
    14. console.log(s);
    15. console.log(s.age);
    16. console.log(s.name);
    17. s.sayName();

  • 相关阅读:
    【杂记-浅谈LSA链路状态通告】
    Java 数据结构篇-实现单链表核心API
    Android Studio Giraffe | 2022.3.1
    PHP简单实现预定义钩子和自定义钩子
    js中ECharts基础
    基于单片机的语音小车设计
    计组+OS——中断之外部中断和内部中断以及单中断和多重中断
    Vue开发中常用的 js处理数组的方法
    [附源码]计算机毕业设计springboot交通事故档案管理系统
    自定义注解+AOP解决重复提交的问题
  • 原文地址:https://blog.csdn.net/m0_58190023/article/details/128049845