震惊,这是JavaScript对象继承的方式

1.原型链

以原型链的方式来实现继承,但是这种实现方式存在的缺点是,在包含有引用类型的数据时,会被所有的实例对象所共享,容易造成修改的混乱。还有就是在创建子类型的时候不能向(super)父类传递参数

仅继承了原型成员  

// 父类
        function F(name, age, gender) {
            this.name = name
            this.age = age
            this.gender = gender
        }
        // 父类的原型成员
        F.prototype.eat = function () {
            console.log(this.name + "爱睡觉");
        }
        // 子类
        function S(name, age) {
            this.name = name
            this.age = age
        }
        // 原型链继承:子类的构造下指向父类
        S.prototype = new F()//没法动态改变F实例
        console.log(S.prototype.constructor);//F
        // 子类的构造器指向父类 修改原型指向之后再改回来
        S.prototype.constructor = S
​
        var s = new S("小白", 20)
        console.log(s);
        s.eat()
        console.log(s.gender); 
        //只能继承原型成员,不能继承实例成员 undefined,因为newF时未指定
        console.log(s.constructor);//S
//————————————————
//原文链接:https://blog.csdn.net/weixin_70563937/article/details/126177360

2.借用构造函数

借用构造函数的方式,这种方式是通过在子类型的函数中调用父类的构造函数来实现的,这一种方法解决了不能向父类传递参数的缺点,但是它存在的一个问题就是无法实现函数方法的复用,并且父类原型定义的方法子类型也没有办法访问到。

仅继承实例成员

       
 // 父类
        function F(name, age,gender) {
            this.name = name
            this.age = age
            this.gender=gender
     //tips:当被S借用时。考虑清楚,没有new,当作普通函数用的,里面的this是S
        }
        // 父类的原型成员
        F.prototype.eat = function () {
            console.log(this.name + "爱睡觉");
        }
        // 子类
        function S(name, age,gender) {
            console.log(this);
            // 函数里面的this指向window
            // 将父类的构造函数添加给子类的实例对象
            // 把父类的构造函数在子类中运行一次
            this.myFun = F
            // 使用子类的实例 调用这个方法(对象.方法())
            this.myFun(name, age, gender)//形参个数要一样
            // 只用一次 用完了删除
            delete this.myFun
            //其实这里可以用apply或者call的
        }
        // S()
        var p = new S("小白", 10,"女")
        console.log(p);
        console.log(p.gender);
        // 只能使用实例成员 不能使用原型成员
        // p.eat()
​
//————————————————
//原文链接:https://blog.csdn.net/weixin_70563937/article/details/126177360

3.组合继承

组合继承是将原型链和借用构造函数组合起来使用的一种方式。通过 借用构造函数的方式来实现类型的属性的继承,通过将子类型的原型设置为父类的实例来实现方法的 继承。这种方式解决了上面的两种模式单独使用时的问题,但是由于我们是以父类的实例来作为子类型的原型,所以调用了两次父类的构造函数,造成了子类型的原型中多了很多不必要的属性 。

继承了实例成员和原型成员

        // 父类
        function Person(name, age, gender) {
            this.name = name
            this.age = age
            this.gender = gender
        }
        // 父类的原型成员
        Person.prototype.eat = function () {
            console.log(this.name + "爱睡觉");
        }
        // 子类
        function Son(name, age, gender, score) {
            // 借用构造函数继承,这么些更好,指定了作用域
            // Person.call(this, name, age)
            Person.apply(this, [name, age, gender])
            // 自己身上的属性
            this.score = score
        }
        // 原型链继承
        Son.prototype = new Person()
        // 把this指向指回去
        Son.prototype.constructor = Son
        // 子类的原型成员
        Son.prototype.Score = function () {
            console.log(this.name + "的分数为" + this.score);
        }
        // 实例化
        var p = new Son("小白", 20, "女", 100)
        console.log(p);
        p.eat()  //使用父类的原型成员方法
        p.Score()//使用自己的原型成员方法
        console.log(p.name + "的分数为" + p.score);//使用父类的name属性
​
//————————————————
//原文链接:https://blog.csdn.net/weixin_70563937/article/details/126177360

4.原型式继承

原型式继承的主要思路就是基于已有的对象来创建新的对象,实现 的原理是,向函数中传入一个对象,然后返回一个以这个对象为原型的对象。这种继承的思路主要不是 为了实现创造一种新的类型,只是对某个对象实现一种简单继承,ES5 中定义的 Object.create() 方法就 是原型式继承的实现。缺点与原型链方式相同。 原型链更混乱。

        // 父类
        function F(name, age, gender) {
            this.name = name
            this.age = age
            this.gender = gender
        }
        // 父类的原型成员
        F.prototype.eat = function () {
            console.log(this.name + "爱睡觉");
        }
        // 子类
        function S(name, age) {
            this.name = name
            this.age = age
        }
        // 把父类的原型成员赋值给子类的原型成员
        S.prototype = F.prototype
        var p = new S("小白", 20)
        p.eat()
        console.log(p.gender);//只能继承原型成员,不能继承实例成员 undefined
        console.log(p.constructor);//子类的构造器指向父类
        // 原型链混乱
        //缺点:F的原型又是S的原型,那这个原型的constructor应该指向谁
​
//————————————————
//原文链接:https://blog.csdn.net/weixin_70563937/article/details/126177360

5.寄生式继承

寄生式继承,寄生式继承的思路是创建一个用于封装继承过程的函数,通过传入 一个对象,然后复制一个对象的副本,然后对象进行扩展,最后返回这个对象。这个扩展的过程就可以 理解是一种继承。这种继承的优点就是对一个简单对象实现继承,如果这个对象不是自定义类型时。缺点是没有办法实现函数的复用

        // 父类
        function F(name, age, gender) {
            this.name = name
            this.age = age
            this.gender = gender
        }
        // 父类的原型成员
        F.prototype.eat = function () {
            console.log(this.name + "爱睡觉");
        }
        // 子类,拓展了父类的一个实例
        function S(name, age) {
            let clone = F(name, age); // 继承一个对象 返回新函数
            clone.say = function(){console.log('我是儿子')}
            return clone
        }
   
        var p = S("小白", 20)
        p.eat()
        console.log(p.gender);//未定义,所以undefined
        console.log(p.constructor);//子类的构造器指向父类
​
​

6.寄生组合继承

寄生式组合继承,组合继承的缺点就是使用超类型的实例做为子类型的原型,导 致添加了不必要的原型属性。寄生式组合继承的方式是使用超类型的原型的副本来作为子类型的原型, 这样就避免了创建不必要的属性。

         function Person(name, age) {
            this.name = name;
            this.age = age;
            Person.prototype.eat = function () {
                console.log(this.name + "挨次鱼");
            };
        }
 
        function Student(score, name, age) {
            // 继承原型成员
            Student.prototype.__proto__ = Person.prototype;
            // 继承实例成员
            Person.call(this, name, age);//有点像python 
            // 自己的实例成员
            this.score = score;
            // 自己的原型成员
            Student.prototype.test = function () {
                console.log(this.name + "成绩非常好,每次都" + this.score + "分!");
            };
        }
 
        let s1 = new Student(100, "张三", 12);
        console.log(s1);
        s1.eat()
        s1.test()
//————————————————
//原文链接:https://blog.csdn.net/weixin_70563937/article/details/126177360

猜你喜欢

转载自blog.csdn.net/qq_42533666/article/details/129087003