小球运动案例重新理解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();