一、原型链继承
核心:将父类的实例作为子类的原型,主要是利用了Dog.prototype = new Animal(),这样Dog.prototype.proto就指向了Animal.prototype,从而将子类Dog的原型和父类Animal的原型相关联
function Animal() {this.name = 'animal'this.arr = []this.eat = function() {console.log('animal eat')}}Animal.prototype.age = 18function Dog() {this.break = function() {console.log('dog bark');}}// Dog.prototype.__proto__ = Animal.prototype// Dog.prototype 指向 Animal的实例Dog.prototype = new Animal();// h1.__proto__ = Dog.prototypelet h1 = new Dog();console.log(h1.arr)h1.arr.push(1)let h2 = new Dog();console.log(h2.arr)
特点:
- 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
- 父类新增原型方法/原型属性,子类都能访问到
缺点:
来自父类引用类型的实例属性是所有实例共享的,即属性没有私有化,原型上属性的改变会作用到所有的实例上
二、构造函数继承
核心:在调用子类构造函数时内部使用call或apply来调用父类的构造函数,从而达到了使用父类的的构造函数来增强子类实例的效果,等于是复制父类的实例属性给子类(没有用到原型)
function Super(){this.flag = true;}function Sub(){Super.call(this) //如果父类可以需要接收参数,这里也可以直接传递}var obj = new Sub();
特点:
1. 实现了属性的私有化
2. 创建子类实例时,可以向父类传递参数
3. 可以实现多继承(call多个父类对象)
缺点:
1. 实例并不是父类的实例,只是子类的实例
2. 只能继承父类的实例属性和方法,不能继承原型属性/方法
3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
三、组合继承
核心:结合了构造函数继承和原型链继承
function Super(){this.flag = true;}Super.prototype.getFlag = function(){return this.flag; // 继承方法}function Sub(){this.subFlag = flaseSuper.call(this) // 继承属性}Sub.prototype = new Super();var obj = new Sub();// Sub.prototype = new Super(); 会导致Sub.prototype的constructor指向Super;// 然而constructor的定义是要指向原型属性对应的构造函数的,Sub.prototype是Sub构造函数的原型,// 所以应该添加一句纠正:Sub.prototype.constructor = Sub;Sub.prototype.constructor = Sub; // 修复构造函数指向Super.prototype.getSubFlag = function(){return this.flag;}
