继承的核心就是将父类的原型(prototype)赋值给子类,同时将构造函数(constructor)指回子类,既保证了不会有多余的父类属性,又保证子类能找到自身的构造函数。
1.原型链的继承
1 function Father(){ 2 this.firstName = 'wang', 3 this.action = function(){ 4 console.info('super') 5 } 6 } 7 Father.prototype.sayHi = function(){ 8 console.info('hi') 9 } 10 // 子类的原型指向父类的原型 11 Son.prototype = Father.prototype 12 Son.prototype.constructor = Son // 需要手动将constructor指回来,不然构造函数指向父类 13 // 子类只能继承父类原型上的属性和方法,不能继承父类本身的属性 14 let s = new Son() 15 s.sayHi() // hi 16 console.info(s.firstName) //获取不到父类自身的属性,undefined 17 console.info(s.action) //获取不到父类自身的属性,undefined
弊端:需要手动改回constructor,不能继承父类自身属性
基于原型的继承还有一种实现:
1 function Father(){ 2 this.data = [1] 3 this.firstName = 'wang', 4 this.action = function(){ 5 console.info('super') 6 } 7 } 8 Father.prototype.sayHi = function(){ 9 console.info('hi') 10 } 11 function SonOther(){ 12 } 13 SonOther.prototype = new Father() 14 SonOther.prototype.constructor = SonOther 15 let so1 = new SonOther() 16 let so2 = new SonOther() 17 // 能继承父类自身的属性 18 console.info(so1.firstName) // wang 19 so2.sayHi() // hi 20 // 但是数据是共享的 21 so1.data.push(2) 22 console.info(so2.data) // [1, 2]
弊端:需要手动改回constructor,子类对象属性共享
2.借助构造函数继承
1 function Son(){ 2 Father.call(this) // Father.apply(this) 3 } 4 5 let s = new Son() 6 let s2 = new Son() 7 console.info(s.data.push(2)) 8 console.info(s.data, s2.data) // [ 1, 2 ] [ 1 ] 不会共享数据 9 console.info(s.sayHi) // 不能继承父类原型中的方法
弊端:只能继承父类自身的属性
3.组合式继承 构造函数+原型链
1 function Son(){ 2 Father.call(this) // Father.apply(this) 3 } 4 5 Son.prototype = new Father()
优点:能继承父类自身及原型链上的方法
弊端:调用了两次父类的构造函数,造成内存浪费
4.寄生式继承
通过一个函数在内部给对象添加属性和方法
1 let father = { 2 name: 'f', 3 age: 30 4 } 5 6 function createObj(original){ 7 let obj = Object.create(original) 8 obj.sayHi = function(){ 9 console.info('hi') 10 } 11 return obj 12 } 13 14 let s = createObj(father) 15 console.info(s.name) 16 s.sayHi() 17
弊端:子类对象共享属性
5.寄生组合继承
1 function inheritPrototype(subType, superType){ 2 let prototype = Object.create(subType.prototype) 3 subType.prototype = prototype 4 subType.prototype.constructor = subType 5 } 6 7 function Son(){ 8 Father.call(this) 9 } 10 inheritPrototype(Son, Father) 11 12 let son = new Son() 13 console.info(son)
6.类的继承
要点:使用extends指明父类,构造函数中写super
1 class Parent { 2 constructor(){ 3 this.name = 'f' 4 } 5 sayHi(){ 6 console.info('hi') 7 } 8 } 9 10 class Child extends Parent { 11 constructor(value){ 12 super(value) 13 this.val = value 14 } 15 } 16 17 let child = new Child('899.5') 18 console.info(child.name, child.val) // f 899.5 19 child.sayHi() // hi