继承(面试问到)
原型链继承
// 原型链继承 function father () { this.name = '父' } father.prototype.getName = () => { console.log('父类方法') } function son () { this.name = '子' } son.prototype.getAge = () => { console.log('子类age') } son.prototype = new father() son.prototype.getSonName = () => { console.log('子类方法') } var s = new son() s.getName() son.prototype.__proto__.getName = () => { console.log('子类改变父类') } s.getName() var f = new father() f.getName()
缺点:
父类使用this声明的属性(私有属性和公有属性)被所有实例共享,在多个实例之间对引用类型数据操作会互相影响。
创建子类实例时,无法向父类构造函数传参
extends继承
1 class fatch { 2 constructor(name,age) { 3 this.name = name; 4 this.age = age 5 } 6 get () { 7 console.log('父类') 8 console.log(this.name,this.age,this.job) 9 } 10 } 11 12 class son extends fatch { 13 constructor(name,age,job) { 14 super(name,age) 15 this.job = job 16 } 17 getInfo () { 18 console.log(this.name,this.age,this.job) 19 } 20 } 21 22 let s = new son('1','2','3') 23 s.get() 24 s.getInfo() 25 console.log(fatch.prototype.__proto__) 26 console.log(son.prototype.__proto__)
注意:
如果子类没有定义constructor方法,这个方法会被默认添加,代码如下。也就是说,不管有没有显式定义,任何一个子类都有constructor方法。
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。
借用构造函数继承(call)
1 function fatch (name,age) { 2 this.name = name 3 this.age = age 4 } 5 6 fatch.prototype.getFname = function () { 7 console.log('父') 8 console.log(this.name,this.age,this.job) 9 } 10 function son (name,age,job) { 11 fatch.call(this,name,age) // 继承自fatch 12 this.job = job 13 } 14 son.prototype.getFname = function () { 15 console.log('父') 16 console.log(this.name,this.age,this.job) 17 } 18 var s = new son(4,5,6) 19 var f = new fatch(1,2,3) 20 f.getFname() 21 s.getFname()
优点:
可以向父类传递参数,而且解决了原型链继承中:父类属性使用this声明的属性会在所有实例共享的问题。
缺点:
- 只能继承父类通过this声明的属性/方法,不能继承父类prototype上的属性/方法。
- 每次子类实例化都要执行父类函数,重新声明父类this里所定义的方法,因此父类方法无法复用