1.原型继承
就是你的原型赋值给我的原型 Cat.prototype = Animal.prototype 继承后可以通过.prototype对原型进行修改,这就会导致影响其他继承该原型的对象的属性,这也是原型继承的缺点
// 抽象:所有动物都会吃
function Animal() {}
Animal.prototype.desc = '这是一种动物'
Animal.prototype.eat = function(){
console.log('哇呜,吃..',this.name,this.desc);
}
function Cat(name){
this.name = name;
}
// 原型继承:你的原型赋值给我的原型
Cat.prototype = Animal.prototype;
new Cat('小猫').eat();
// 对原型进行修改
Cat.prototype.desc = 'desc变成了一只小狗';
Cat.prototype.eat = function(){
console.log('狗的原型受到了影响!');
}
function Dog(name){
this.name = name;
}
// 原型继承:你的原型赋值给我的原型
Dog.prototype = Animal.prototype;
new Dog('小狗').eat();
2. 构造函数继承
思想是利用父类构造函数实现数据共享,缺点也是子类可以随意修改父类的数据
// 父类
function Animal(name) {
this.name = name;
this.eat = function () {
console.log(this.name, '吃吃吃,就知道吃')
}
}
// 子类调用父类构造函数
function Cat(name) {
Animal.call(cat, name); //调用时临时指定Animal this指向为传入的cat
}
new Cat('Green').eat();
3. 组合继承(原型继承+构造函数继承)
组合继承 = this绑定父类构造函数 + 将原型=父类原型
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function () {
console.log('哇呜,吃..', this.name);
}
// 组合继承
function Cat(name) {
Animal.call(this, name);
}
Cat.prototype = Animal.prototype;
new Cat('XXX').eat();
4. 派生继承
1)用Object.create()继承时创建新的对象,解决了公共原型被修改影响所有实例的问题; 2).prototype.constructor = XX 将原型构造函数指向自己的构造函数,掰回歪曲的构造函数; 3)通过.prototype[Symbol.toStringTag]来修改子类原型的[类型描述]以及父类原型的[类型描述];
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function () {
console.log('哇呜,吃..', this.name);
}
// 【重点3】修改原型的[类型描述]
Animal.prototype[Symbol.toStringTag] = Animal.name;
// 组合继承
function Cat(name) {
Animal.call(this, name);
}
// 【重点1 派生】:解决公共原型被修改影响所有实例的问题
Cat.prototype = Object.create(Animal.prototype);
// 【重点2】掰回歪曲的构造函数
Cat.prototype.constructor = Cat;
// 【重点3】修改原型的[类型描述]
Cat.prototype[Symbol.toStringTag] = Cat.name;
// 测试
var dogPrototype = Object.create(Animal.prototype);
console.log(Cat.prototype === dogPrototype); // false
var c1 = new Cat('XXX');
console.log('小猫:', c1);
c1.eat();