小球运动案例重新理解Es6继承和寄生组合式继承


首先呢,es6的继承是要比es5简单的,所以我们先吧我们之前写过的那个面向对象对象的小球,再重新拿过来 什么是继承呢,就是根据原有的方法和属性,想去创建新的对象的时候,只需要根据已有的对象去new一个新对象出来 new出来的对象具有原有类的方法和属性,不一样的地方我们再去添加他的新的属性和方法,我的理解就是这样的,那我们先来看下效果

 这个小方块是根据原来的小球new出来的一个新对象,我们添加了新的属性,取消了他的圆角,通过这个例子我们来理解一下es6的继承

es5中的类和es6中的类的写法也是有区别的,这个在之前的代码中也有写过





    
    Title



    


那么接下来我再重新整理出我们es5中的继承的,因为其他的继承稍微有点缺陷,这个缺陷可以自行百度,所以我们以后都是用寄生式继承来使用

js中我们常用的就是组合继承,但是组合继承最大的 问题就是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是 在子类型构造函数内部。

没错,子类型最终会包含超类型对象的全部实例属性,但我们不得不在调用子 类型构造函数时重写这些属性

再写个小案例我们先来对比一下es5中组合继承和寄生组合式继承

首先是组合继承

function Ainimal( height, weight ) {
                this.height = height;
                this.weight = weight;
            }
            Ainimal.prototype.run = function () {
                console.log( "我会跑" )
            }
            Ainimal.prototype.jump = function () {
                console.log( "我会跳" )
            }

            function Cat( height, weight ) {
                Ainimal.call( this, height, weight )
            }
            Cat.prototype = new Ainimal();
            Cat.prototype.wash = function () {
                console.log( "我是猫,我会洗脸" )
            }

            function Dog( height, weight ) {
        //第二次调用Ainimal()方法 Ainimal.call(
this, height, weight ) }
        //第一次调用Ainimal()方法 Dog.prototype
= new Ainimal() Dog.prototype.shake = function () { console.log( "我是狗,我会摇尾巴" ) } let c = new Cat( 20, 30 ); console.log( c.height, c.weight ) c.wash(); c.run(); c.jump() let d = new Dog( 40, 50 ); console.log( d.height, d.weight ); d.shake(); d.run(); d.jump(); */

在以上的例子中,

在第一次调用Ainimal 构造函数时, Dog.prototype 会得到两个属性height 和 weight;它们都是 Ainimal 的实例属性,只不过 现在位于 Dog 的原型中。当调用 Dog 构造函数时,又会调用一次 Ainimal 构造函数,这 一次又在新对象上创建了实例属性 height 和 weight。于是,这两个属性就屏蔽了原型中的两个同名属性,因此我们使用下面的寄生组合式继承

        function Ainimal( height, weight ) {
            this.height = height;
            this.weight = weight;
        }
        Ainimal.prototype = {

            run: function () {
                console.log( "跑" )
            },
            jump: function () {
                console.log( "跳" )
            }
        };

        function extend( subClass, supClass ) {
            // 创建一个空类,空的构造函数
            function A() {}
            // 设置这个空类的原型是父类的原型,这样保证这个空类和父类一样,但是没有父类构造函数内容
            // 这样就解决直接继承时调用两次构造函数的情况
            A.prototype = supClass.prototype;
            // 将这个与父类相似的类实例化后赋值给子类的原型,这样子类的原型就是这个空类的实例化对象
            // 因此子类的原型里面就有了空类的原型下所有属性和方法
            subClass.prototype = new A();
            // 子类的原型指针指向子类的构造函数
            subClass.prototype.constructor = subClass;
            // 因为可能在子类使用到父类原型
            // 设置子类的属性superClass是父类的原型对象
            subClass.superClass = supClass.prototype;
            // 如果父类原型的指针没有指向父类的构造函数,仍然指向的是对象
            if ( supClass.prototype.constructor === Object.prototype.constructor ) {
                // 将父类的原型指针指向父类构造函数
                supClass.prototype.constructor = supClass;
            }
        }

        function Cat( height, weight ) {
            Ainimal.call( this, height, weight )
        }
        extend( Cat, Ainimal );
        Cat.prototype.wash = function () {
            console.log( "我是猫,我除了跑和跳,我还会洗脸" )
        }
        let c = new Cat( 200, 300 );
        console.log( c.height, c.weight );
        c.wash();
        c.jump();
        c.run();
        // 新建一个狗类
        function Dog( height, weight ) {
            Ainimal.call( this, height, weight )

        }
        extend( Dog, Ainimal );
        Dog.prototype.shake=function(){
            console.log("我是一条小狗,我除了会跑,会跳,我还会摇尾巴")
        }
        let d=new Dog(300,400);
        console.log(d.height,d.weight);
        d.jump();
        d.run();
        d.shake();