想要继承,就必须要提供个父类(继承谁,提供继承的属性)
父类的实例作为子类的原型
function Woman(){ } Woman.prototype= new People(); Woman.prototype.name = 'haixia'; let womanObj = new Woman();优点:
简单易于实现,父类的新增的实例与属性子类都能访问
缺点:
可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面
无法实现多继承
创建子类实例时,不能向父类构造函数中传参数
复制父类的实例属性给子类
function Woman(name){ //继承了People People.call(this); //People.call(this,'wangxiaoxia'); this.name = name || 'renbo' } let womanObj = new Woman();优点:
解决了子类构造函数向父类构造函数中传递参数
可以实现多继承(call或者apply多个父类)
缺点:
方法都在构造函数中定义,无法复用
不能继承原型属性/方法,只能继承父类的实例属性和方法
优点:
不限制调用方式
简单,易实现
缺点:不能多次继承
调用父类构造函数,继承父类的属性,通过将父类实例作为子类原型,实现函数复用
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } Cat.prototype = new Animal();// 感谢 @学无止境c 的提醒,组合继承也是需要修复构造函数指向的。Cat.prototype.constructor = Cat; // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // true特点:
弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法既是子类的实例,也是父类的实例不存在引用属性共享问题可传参函数可复用缺点:
调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
寄生继承首先将一个普通对象twoD克隆进一个叫that的对象,然后扩展that对象,添加更多的属性,最后返回that对象。这种寄生继承就是对原型继承的第二次封装,并且在这第二次封装过程中对继承的对象进行了拓展,这项新创建的对象不仅仅有父类中的属性和方法而且还有新添加的属性和方法。
function object(o) { function F() {}; F.prototype = o; return new F(); } var twoD = { name: '2D shape', dimensions: 2 } function triangle(s, h) { var that = object(twoD); that.name = 'Triangle'; that.getArea = function() {return this.side*this.height / 2;} that.side = s; that.height = h; return that; } var a = triangle(2,16); a.dimensions通过寄生的方式来修复组合式继承的不足,完美的实现继承
**核心:**通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } (function(){ // 创建一个没有实例方法的类 var Super = function(){}; Super.prototype = Animal.prototype; //将实例作为子类的原型 Cat.prototype = new Super(); })(); // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); //true