一.原型链继承
特点:子类型的原型是父类型的一个实例对象 父类新增原型方法或原型属性子类都会访问到 简单易于实现
子类的实例通过 _proto_ 访问到父亲的实例 这样就可以访问父类的私有方法 然后通过 _proto_ 指向父类的 prototype 获得父亲原型上的方法 这样做到将父类的私有 公有方法和属性都当做子类的公有属性和方法
缺点:无法实现多继承
来自原型对象的所有属性被所有实例共享
创建子类实例时 无法向父类构造函传参
想给子类新增属性和方法要在 son.prototype = new fa() 之后执行 不能放到构造器
二.构造函数继承
特点:在子类构造函数中用 call() 调用父类构造函数 只能继承父类的属性和方法 不能继承父类原型的属性和方法
解决了原型链继承者子类实例共享父类引用属性的问题 创建子实例时可以向父类传递参数
可以多继承 call 多个夫类对象
缺点:实例并不是父类的实例 只是子类的实例
只能继承父类的实例属性和方法 不能继承原型属性和方法
不能函数复用 每个子类都有父类实例函数的副本 影响性能
三.原型链 + 构造函数
通过调用父类构造 继承父类的属性并保留传参的优点 通过将父类实例作为子类原型实现函数复用
优点:可以继承实例属性 方法 也可以继承原型属性方法
不存在引用属性共享问题
可传参
函数可复用
缺点:调用两次父类构造函数生成两份实例
function Person(name, age) { this.name = name, this.age = age, this.setAge = function () { } } Person.prototype.setAge = function () { console.log("111") } function Student(name, age, price) { Person.call(this,name,age) this.price = price this.setScore = function () { } } Student.prototype = new Person() Student.prototype.constructor = Student Student.prototype.sayHello = function () { } var s1 = new Student('Tom', 20, 15000) var s2 = new Student('Jack', 22, 14000)
四.组合继承优化1
通过父类原型和子类原型指向同一对象 子类可以继承到父亲的公有方法当作自己的公有方法 不会初始化两次实例方法 避免组合继承的缺点
优点:不会初始化两次实例方法 避免组合继承的缺点
缺点:没办法辨别实例是子类还是父类创造的 子类和父类构造函数指向是同一个
五.组合继承优化2
借助原型可以基于已有的对象来创建对象 var B = Object.create(A) 以 A 对象为原型 生成 B 对象 B 继承 A 所有属性和方法
核心:B.prototype = Object.create(A.prototype)
B.prototype.constructor = B
六.ES6 中 class 的继承
class extends 继承
优点:操作方便
缺点:不是所有浏览器都支持 class 关键字