一 原理
在子类的构造函数中,通过call ( ) 或 apply ( ) 的形式,调用父类的构造函数来实现继承。
function Fruit(name){ this.name = name; this.eat = function(){ console.log('eat'); }; } Fruit.prototype.desc = function(){ console.log('desc'); }; function Mango(name,level){ Fruit.call(this,name); this.level = level; } let mango1 = new Mango('泰国芒果','优'); console.log(mango1); let mango2 = new Mango('海南芒果','良'); console.log(mango2); // 都是子类实例的私有属性,没有从父类共享 console.log(mango1.name == mango2.name); // false // 没有继承父类的原型对象中的方法 console.log(mango1.desc); // undefined // 不支持instanceof console.log(mango1 instanceof Fruit); // false console.log(mango2 instanceof Fruit); // false // 无法复用父类的实例方法 console.log(mango1.eat === mango2.eat); // false
二 优点
1 解决了原型链继承方式中,子类的对象会共享父类构造函数的原型对象的问题。
2 创建子类的对象时,可以向父类构造函数中传递参数。
3 可以实现多继承(call/apply多个父类的构造函数)
三 缺点
1 创建的实例并不是父类的实例,只是子类的实例。
2 没有拼接原型链,不能使用instanceof。因为子类的实例只继承了父类的实例属性/方法,没有继承父类的构造函数的原型对象中的属性/方法。
3 每个子类的实例都持有父类的实例方法的副本,浪费内存,影响性能,而且无法实现父类的实例方法的复用。
每次创建mango实例,都要创建其私有的eat函数。有多少个mango实例,就创建多少个eat函数。无法实现eat函数的复用。