一 原理
子类的构造函数的原型对象,是父类的构造函数创建的实例。
function Fruit(){ this.name = '水果'; this.nutrition=['维生素','膳食纤维']; } Fruit.prototype.eat = function(){ console.log('eat'); }; function Mango(){ } // 继承父类的方法 Mango.prototype = new Fruit(); // 修改父类的构造函数的原型对象的constructor属性: // 父类的实例会继承原型对象的constructor属性,从而父类的实例的constructor属性都指向父类的构造函数。仅此而已。 Mango.prototype.constructor = Mango; // 添加子类的方法 Mango.prototype.taste = function(){ console.log('taste'); }; let mango1 = new Mango(); let mango2 = new Mango(); // 子类的实例共享原型对象中的属性/方法 console.log(mango1.name,mango2.name); // 水果 水果 console.log(mango1.nutrition === mango2.nutrition); // true console.log(mango1.eat === mango2.eat) // true // 原型对象中的属性是基础数据类型:不能被子类直接修改 mango1.name = '泰国芒果'; mango2.name = '海南芒果'; console.log(mango1.__proto__.name,mango2.__proto__.name); // 水果 水果 console.log(mango1.name,mango2.name); // 泰国芒果 海南芒果 // 原型对象中的属性是对象类型:可以被子类直接修改。 mango1.nutrition.push('柠檬酸'); console.log(mango2.nutrition); // ["维生素", "膳食纤维", "柠檬酸"] // 原型链 console.log(mango1 instanceof Mango); // true console.log(mango1 instanceof Fruit); // true
二 优点
拼接了原型链。子类的实例可以从父类继承属性/方法,子类的实例是父类的实例。
三 缺点
1 子类的构造函数无法向父类的构造函数传参。定义子类的构造函数时,继承就确定了,跟子类的构造函数的执行无关。
2 子类的实例共享原型对象的属性/方法,互相干扰。
3 不能实现多继承。 原型对象只能有一个。