【前端全家桶】JS 面向对象知识 OOP 类与实例 继承的几种方式

写在开头

大家好,这里是 lionLoveVue,基础知识决定了编程思维,学如逆水行舟,不进则退。金三银四,为了面试也还在慢慢积累知识,Github上面可以直接查看所有前端知识点梳理, github传送门,觉得不错,点个Star★,好运连连,Offer终究鼠于你,持续更新中。另外,也可以关注微信公众号: 小狮子前端Vue,源码以及资料今后都会放在里面。
一直想着成为一个up主,正值时间挺多的,4月份左右面试的面经我会制作视频去分享,赶快捧个场吧。 哔哩哔哩:一百个Chocolate

面向对象

题目

类与实例

  • 类的声明
  • 生成实例

类与继承

  • 如何实现继承
  • 继承的几种方式

类与实例

<body>
    <script>
        /* 类的声明 */
        function Animal(){
            this.name='aaa';
        }
        /* ES6中的class的声明 */
        class Animal2{
            constructor(){
                this.name = 'bbb';
            }
        }
        /* 实例化一个类 */
        console.log(new Animal(),new Animal2());
    </script>
</body>

效果

类与继承

方法一:借助构造函数来实现继承

		/* 借助构造函数来实现继承 */
        function fruit(){
            this.name = 'fruit';
        }
        function apple(){
            fruit.call(this);
            this.type='apple';
        }
        console.log(new apple);

上述这种方式,是通过改变fruit构造函数运行时this指向,指向了apple上,但是fruit原型链上的东西并没有被继承。

		/* 借助构造函数来实现继承 */
        function fruit(){
            this.name = 'fruit';
        }
        fruit.prototype.eat = function(){
            console.log('吃水果啦!');
        }
        function apple(){
            fruit.call(this);
            this.type='apple';
        }
        console.log(new apple().eat());


因此,通过构造函数来实现的继承,只能继承父类构造函数的属性,如果原型prototype上面还有方法甚至原型链上的方法,不会继承。

方法二:借助原型链实现继承

/* 借助原型链实现继承 */
function fruit(){
  this.name = 'fruit';
}
function apple(){
  this.type='apple';
}
apple.prototype = new fruit();
console.log(new apple());

掌握之前原型链相关的知识,下面的等式应该就比较容易理解了

但这种继承方式也是有缺点的,下文来探讨这个问题:

        /* 借助原型链实现继承 */
        function fruit(){
            this.name = 'fruit';
            this.arr = [1,2,3];
        }
        function apple(){
            this.type='apple';
        }
        apple.prototype = new fruit();
        var app1 = new apple();
        var app2 = new apple();
        app1.arr.push(4);
        console.log(app1,app2);

从上述结果来看,当我们修改某一个对象时,该函数的所有新出的实例对象都会跟着改变,这就造成了污染问题,肯定不是我们面向对象思想所想要的。(因为它们引用的是同一个父类实例对象)

方式三:组合方式实现继承

这种方式就是结合前两种的优点,弥补它们的缺点。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>面向对象</title>
</head>
<body>
    <script>
        /* 关于继承的几种方式
        **使用方法:
        **读者按需将对应模块注释取消掉即可 
        */

        /* 借助原型链实现继承 */
        /*function fruit(){
            this.name = 'fruit';
            this.arr = [1,2,3];
        }
        function apple(){
            this.type='apple';
        }
        apple.prototype = new fruit();
        var app1 = new apple();
        var app2 = new apple();
        app1.arr.push(4);
        console.log(app1,app2);*/

        /* 组合方式实现继承 */
        /**
        *此方法的缺点:new fruit() 父类构造函数执行了两次,可以但没必要
        */
        function fruit(){
            this.name = 'fruit';
            this.arr = [1,2,3];
        }
        function apple(){
            fruit.call(this);
            this.type='apple';
        }
        apple.prototype = new fruit();  //这里拿的是父类的实例,没有自己的constructor
        var app1 = new apple();
        var app2 = new apple();
        app1.arr.push(4);
        //console.log(app1,app2);
        //console.log(app1.constructor,app2.constructor)   
        
        /* 组合方式实现继承优化1 */
        function fruit1(){
            this.name = 'fruit';
            this.arr = [1,2,3];
        }
        function apple1(){
            fruit.call(this);
            this.type='apple';
        }
        apple1.prototype = fruit1.prototype;  //这里拿的是父类的原型对象,但依旧没有自己的constructor
        var app3 = new apple1();
        var app4 = new apple1();
        app3.arr.push(4);
        //console.log(app3,app4);
        //判断实例
        //console.log(app3 instanceof apple1);
        //console.log(app3 instanceof fruit1); //这里无法判断当前对象是由父类产生的实例对象还是由子类产生的实例对象
        //判断构造函数
        //console.log(app3.constructor);      
        //console.log(app4.constructor);       //因为和父类的原型对象是一个对象,导致constructor也是指向的父类的constructor,无法判断自己

        /* 组合方式实现继承优化2 */
        function fruit2(){
            this.name = 'fruit';
            this.arr = [1,2,3];
        }
        function apple2(){
            fruit.call(this);
            this.type='apple';
        }
        apple2.prototype = Object.create(fruit2.prototype);  //这里使用Object.create()方法,和之前直接用fruit2.prototype来说,它创建了一个中间对象,和父类不是指向同一个区域了
        //这样就能区分父类和子类的原型对象了,达到父类和子类原型对象的隔离效果
        apple2.prototype.constructor = apple2;  //由于隔离了父类子类的原型对象,我们就可以指定子类自己的constructor
        var app5 = new apple2();
        var app6 = new apple2();
        app5.arr.push(4);
        console.log(app5,app6);
         //判断实例
        console.log(app5 instanceof apple2);
        console.log(app5 instanceof fruit2); //因此,这里可以判断当前对象是由父类产生的实例对象还是由子类产生的实例对象
        //判断构造函数
        console.log(app5.constructor);       //指向的是自己的constructor


    </script>

    
</body>
</html>

结尾

如若本文有瑕疵需修改的地方,请提出来,谢谢您的贡献!

欢迎关注微信公众号:小狮子前端Vue

谢谢您的支持!✿✿ヽ(°▽°)ノ✿

学如逆水行舟,不进则退
发布了598 篇原创文章 · 获赞 1827 · 访问量 33万+

猜你喜欢

转载自blog.csdn.net/weixin_42429718/article/details/105308322