【学习笔记65】JavaScript的继承

一、认识继承

        function Person(name) {
            this.name = name
        }
        Person.prototype.sayName = () => {
            console.log('name')
        }

        function Stu(age) {
            this.age = age
        }
    
        const s = new Stu(18)

        console.log(s)  // {age: 18}

说明: 

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

 二、原型继承

  • 核心:  就子类的原型指向父类的实例化对象
  • 优点:  实现了继承
  •  缺点: 继承了属性, 但是不在自己身上,失去了自己的原型
        // 1. Person父类
        function Person(name) {
            this.name = name
        }
        Person.prototype.sayName = () => {
            console.log('name')
        }

        // 2. Person子类
        function Stu(age) {
            this.age = age
        }
        Stu.prototype.abc = () => {
            console.log(123)
        }
        // 原型的继承
        Stu.prototype = new Person('QF001')
        Stu.prototype.abc2 = () => {
            console.log(456)
        }
        
        const s = new Stu(18)

        // 需求:使用Person内部的name和sayName 方法
        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、原型继承的运用

        function Person(name) {
            this.name = name
        }
        Person.prototype.sayName = () => {
            console.log('name')
        }

        // 2. Person子类
        function Stu(age) {
            this.age = age
        }
        Stu.prototype.abc = () => {
            console.log(123)
        }
        // 原型的继承
        Stu.prototype = new Person('QF001')
        Stu.prototype.abc2 = () => {
            console.log(456)
        }
        const s = new Stu(18)

        console.log(s)
        console.log(s.age)
        console.log(s.name)
        s.sayName()

三、借用构造函数继承

  • 核心: 借用 call 方法修改 父类构造函数内部的 this 指向
  • 优点: 将属性继承在自己身上,保留了自己的原型
  • 缺点: 只能继承父类的属性, 不能继承父类原型上的方法
        // 父类
        function Person(name) {
            this.abc = name;
            this.name = name;
        }
        Person.prototype.sayName = () => {
            console.log('name');
        }
        
        // Person的自类
        function Stu(age) {
            this.age = age;
            // .call 改变Stu的this指向父类
            Person.call(this, 'QF002');
        }

        const s = new Stu(18);
        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、运用

        function Person(name) {
            this.abc = name;
            this.name = name;
        }
        Person.prototype.sayName = () => {
            console.log('name');
        }

        function Stu(age) {
            this.age = age;
            Person.call(this, 'QF002');
        }
        const s = new Stu(18);

        // 需求:使用Person内部的name和sayName 方法
        console.log(s);
        console.log(s.age);
        console.log(s.abc);
        console.log(s.name);
        s.sayName()   //报错:只能继承父类的属性, 不能继承父类原型上的方法

四、组合继承

组合继承

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

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

 好处:

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

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

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

        function Person(name) {
            this.abc = name;
            this.name = name;
        }
        Person.prototype.sayName = () => {
            console.log('hello');
        }
        function Stu(age) {
            this.age = age;

            // 2. 利用借用继承, 继承到父类的构造函数内部的属性
            Person.call(this, 'QF001');
        }

        // 1. 利用原型继承, 继承到父类的原型上的方法
        Stu.prototype = new Person();
        const s = new Stu(18);

        console.log(s);
        console.log(s.name);
        s.sayName();

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

五、拷贝继承

 核心:

  • 通过for in遍历父类实例化对象上的所有属性, 拷贝到子类上,
  • 它能够遍历对象内部的属性, 以及原型
        function Person(name) {
            this.name = name;
        }
        Person.prototype.sayName = () => {
            console.log('name');
        }

        function Stu(age) {
            this.age = age;
            const p = new Person('QF001');

            for (let key in p) {
                Stu.prototype[key] = p[key];
            }
        }
        Stu.prototype.abc = () => {
            console.log(123);
        }

        const s = new Stu(18);
        console.log(s);

运用

        function Person(name) {
            this.name = name;
        }
        Person.prototype.sayName = () => {
            console.log('name');
        }

        function Stu(age) {
            this.age = age;
            const p = new Person('QF001');

            for (let key in p) {
                Stu.prototype[key] = p[key];
            }
        }
        Stu.prototype.abc = () => {
            console.log(123);
        }
        const s = new Stu(18);

        // // 需求:使Person内部的name何sayName方法
        console.log(s);
        console.log(s.age);
        console.log(s.name);
        s.abc();
        s.sayName();

六、ES6 类的继承

ES6 类的继承

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

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

注意:

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

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

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

        function Person (name) {
            this.name = name;
        }
        Person.prototype.sayName = function () {
            console.log('name');
        }

        class Stu extends Person {
            constructor(age) {
                super('QF001');
                this.age = age;
            }
        }

        const s = new Stu(18);
        console.log(s);
        console.log(s.age);
        console.log(s.name);
        s.sayName();

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值