ES5继承
1. 原型链继承
function Zoo() {
this.zoo = '动物园';
}
function panda(name) {
this.name = name;
}
panda.prototype = new Zoo();
var animal = new panda('熊猫');
console.log(animal.zoo + '里面有一只' + animal.name);
缺点:
不能向父类构造函数(Zoo)传递参数
2. 构造函数继承
——在子类型构造函数的内部调用父类构造函数,使用
apply()
和
call()
方法将this指向子类
function Zoo(zoo) {
this.zoo = zoo;
}
function panda(zoo, name) {
Zoo.call(this,zoo); // 把 Zoo的this 指向panda
this.name = name;
}
var animal = new panda('动物园','熊猫');
console.log(animal.zoo + '里面有一只' + animal.name);
缺点:
无法调用父类原型上的方法 例如:
Zoo.prototype.sleep = function() {
console.log('要睡觉觉了!');
}
console.log(animal.sleep()); // TypeError: animal.sleep is not a function
3. 组合继承
——将原型链继承和构造函数继承组合到一起。使用原型链继承实现对原型属性和方法的继承,用借用构造函数继承实现对父实例属性的继承。这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性
function Zoo(zoo) {
this.zoo = zoo;
}
Zoo.prototype.sleep = function() {
console.log('要睡觉觉了!');
}
function panda(zoo, name) {
Zoo.call(this,zoo); // 把 Zoo的this 指向panda
this.name = name;
}
panda.prototype = new Zoo();
var animal = new panda('动物园','熊猫');
console.log(animal.zoo + '里面有一只' + animal.name);
animal.sleep()
缺点:
会调用两次超类型构造函数,一次是在创建子类型原型的时候,一次是在子类型构造函数的内部,占用内存。
4. 寄生组合式继承
——寄生组合式继承是对组合继承的进一步优化。我们先看一下为什么要写这个语句。
panda.prototype = new Zoo();
我们无非是想让panda继承Zoo的原型。但是我们为什么不直接写成这样呢?
panda.prototype = Zoo.prototype
——这样写确实可以实现子类对象对父类对象原型的继承。但是这样写的话:所有继承该父类的子类对象的原型都指向同一个了。也就是说SubType不能有自己的原型了。这显然不是我们想要的。
——既然不能直接继承,那可不可以间接继承Zoo.prototype呢。这就是最终的解决方案:间接组合式继承。
——我们让一个对象去指向Zoo.prototype,然后让panda.prototype指向这个函数产生的对象不就可以了嘛。
——核心函数:
function indirect(son, father) {
var target = Object.create(father.prototype); // 也可以直接写var target = father.prototype; father.prototype本身就是一个对象,万物皆对象
target.constructor = son;
son.prototype = target;
}
function Zoo(zoo) {
this.zoo = zoo;
}
Zoo.prototype.sleep = function() {
console.log('要睡觉觉了!');
}
function panda(zoo, name) {
Zoo.call(this,zoo); // 把 Zoo的this 指向panda
this.name = name;
}
indirect(panda,Zoo);
var animal = new panda('动物园','熊猫');
console.log(animal.zoo + '里面有一只' + animal.name);
animal.sleep()
优点:
只调用了一次Zoo构造函数,因此避免在panda.prototype上创建不必要的,多余的属性,与此同时,原型链还能保持不变,还能正常使用instanceof 和isPrototypeOf(),因此,寄生组合式继承被认为是引用类型最理想的继承范式。
ES6 继承
class Zoo {
constructor(zoo) {
this.zoo = zoo;
}
sleep() {
return '要睡觉觉了!';
}
}
class animal extends Zoo {
constructor(zoo,age) {
super(zoo);
this.age = age;
}
eat() {
console.log('吃完饭饭'+super.sleep()); // 这里的super指代的是父亲构造函数 Zoo 的原型上的方法 Zoo.prototype
}
}
var panda = new animal('上野动物园','5');
console.log(panda.zoo);// 上野动物园
panda.eat();// 吃完饭饭要睡觉觉了!
——Class 可以通过extends关键字实现继承
——子类必须在constructor方法中调用super方法,否则新建实例时会报错。
——这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。
——
super(zoo)
里的参数zoo 是父亲的属性 要是用父类属性需要加上参数