面向对象-原型链继承(上)

220 阅读3分钟

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

温故知新,还记得这张图么?

面向对象1.png

上篇我们讲了原型对象的使用(传送门),今天继续下一个知识点,也就是构造函数的三大特点之一:继承

是什么?有什么用? 我们一步步的了解,开始今天的学习啦~

一、面向对象-继承

1. 概念解析

三个类

  • 超类型
  • 父类型
  • 子类型 举例:
类:  动物  狗类   哈士奇

对于狗类来说
        动物是它的父类型,而哈士奇类是它的子类型
        
对于哈士奇类来说
        狗类是它的父类型,动物类是它的超类型.

继承就是让子类拥有父类的资源

2. 概念解析继承的方式

  • 01-原型链继承
  • 02-借用构造函数继承
  • 03-组合继承
  • 04-原型式继承
  • 05-寄生式继承
  • 06-寄生式组合继承
  • 07-拷贝属性继承

3. 继承的意义

  • 减少代码冗余
  • 方便统一操作
  • 弊端 ---- 耦合性比较强

二、继承-原型链继承-原型链实战

  1. 每个函数都能构建出一个对象, 这个对象内部有个属性指向着这个函数的原型对象
  2. 原型对象本质也是一个对象,也是由另外一个构造函数构造出来, 也指向那个构造函数的原型对象 以上,形成一个链式的结构,就称为是原型链

测试代码

console.log(arr.constructor.name); // Array

console.log(arr.__proto__.constructor.name); // Array

console.log(Array.__proto__.constructor.name); // Function

console.log(Function.__proto__.constructor.name); // Function

console.log(Function.prototype.__proto__.constructor.name); // Object

console.log(Object.prototype.__proto__); // null
console.log(Object.__proto__.constructor.name); // Function

console.log(Array.prototype.__proto__.constructor.name); // Object

图解 原型链.png

三、继承-原型链继承-原型链检索规则

  1. 对象.属性的方法去访问属性的时候,先查找有没有对应的实例属性,如果有那么就直接使用
  2. 如果没有,那么就去该对象的原型对象上面去找,如果有那么就直接使用
  3. 如果没有,那么就接着查找原型对象的原型对象,如果有,那么就直接使用,
  4. 如果没有,那么就继续上面的搜索过程
  5. 直到搜索到Object.prototype为止,如果还是没有找到就返回undefined或者是报错

注意:

  • 原型链搜索的路径越长,查询属性所花费的时间就越多
  • 原则:就近原型

四、继承-原型链继承-0

说明:从这开始,每一个大标题都会有一个问题,然后在下一个标题内容解决掉又继续抛出问题。 以此类推。 未继承效果: stu对象, 访问不到Person里面的任何内容

<script>
        /**
         * 构造函数Person
         * @constructor
         */
        function Person() {
            this.name = 'Jack';
            this.lore = ['html', 'css'];
        }

        Person.prototype.run = function () {
            console.log('跑');
        };


        /**
         * 构造函数Student
         * @constructor
         */
        function Student() {
            this.num = 'Tom';
        }

        var stu = new Student();
        
        console.log(stu);  // Student {num: "Tom"}
        console.log(stu.num); // Tom
        console.log(stu.name); // undefined
        console.log(stu.lore); // undefined
        stu.run(); // 报错 Uncaught TypeError: stu.run is not a function
    </script>

图解 0.png 问题:子对象无法访问到父类的任何东西?

五、继承-原型链继承-1

这里我们都知道查找规则是什么样的了,首先自己没有, 就到原型对象上面查找...

所以我们来解决上面的问题:子对象无法访问到父类的任何东西?

所以我们就考虑到两点:

  • 要不考虑给添加到自己身上
    • 只能自己有
    • 以后的其他对象, 就没了
  • 要不考虑给添加到原型身上 关于两者之间的区别大家可以去尝试尝试,我们就直接给出我这边的解决方案了。

解决方案:修改原型指向比较方便

    <script>
        /**
         * 构造函数Person
         * @constructor
         */
        function Person() {
            this.name = 'Jack';
            this.lore = ['html', 'css'];
        }

        Person.prototype.run = function () {
            console.log('跑');
        };


        /**
         * 构造函数Student
         * @constructor
         */
        function Student() {
            this.num = 'Tom';
        }

        // 让Student的原型对象--->Person的原型对象
        Student.prototype = Person.prototype;

        var stu = new Student();

        console.log(stu); // Student {num: "Tom"}
        console.log(stu.num); // Tom
        stu.run(); // 跑
    </script>

图解

1.png 到了这里,我们会产生一个问题: 无法访问到父类的对象属性? 大家可以思考思考,我们下期来进行解答。

所以明天我们继续,解答一下上面的那个问题,敬请期待!

八、结语

码字画图不易,如果觉得对你有帮助,觉得还不错的话,欢迎点赞收藏~

当然由于是个人整理,难免会出现纰漏,欢迎留言反馈。