ES5 继承
借助构造函数继承(call, apply);无法继承父级原型上属性和方法
function Animal(name, txt) {
console.log('构造函数:Animal', this, name, txt)
this.type = '父类'
this.name = 'Animal_' + name;
this.txt = txt
}
Animal.prototype.getName = function () {
console.log('调用Animal原型上的方法:', this, this.name)
};
function Cat(name) {
console.log('构造函数:Cat', this, name)
this.name = 'Cat_' + name
const txt = '构造函数继承,先创造子类的实例对象this(例如:cat1,cat2),调用call后, 构造函数Animal中的this指向Cat的实例对象'
Animal.call(this, name, txt);
}
const cat1 = new Cat('1');
console.log(cat1.type);
console.log(cat1.name);
原型继承;父级与子级无法动态传参,改变原型会导致所有实例都发生改变
function Animal(name, txt) {
console.log('构造函数:Animal', this, name, txt)
this.type = '父类'
this.name = 'Animal_' + name;
this.txt = txt
}
Animal.prototype.getName = function () {
console.log('调用Animal原型上的方法:', this, this.name)
};
function Cat(name) {
console.log('构造函数:Cat', this, name)
this.name = 'Cat_' + name
const txt = '构造函数继承,先创造子类的实例对象this(例如:cat1,cat2),调用call后, 构造函数Animal中的this指向Cat的实例对象'
Animal.call(this, name, txt);
}
const animal = new Animal("1", '构造函数实例化');
animal.getName();
Cat.prototype = animal;
const cat2 = new Cat('2');
cat2.getName();
组合继承: 借助构造函数继承 + 原型链继承;两次调用父类的构造函数(耗内存)
function Animal(name, txt) {
console.log('构造函数:Animal', this, name, txt)
this.type = '父类'
this.name = 'Animal_' + name;
this.txt = txt
}
Animal.prototype.getName = function () {
console.log('调用Animal原型上的方法:', this, this.name)
};
function Cat(name) {
console.log('构造函数:Cat', this, name)
this.name = 'Cat_' + name
}
const animal = new Animal("1", '构造函数实例化');
Cat.prototype = animal;
const cat2 = new Cat('2');
cat2.getName();
console.log(cat2.name);
寄生组合继承; 可传参可原型继承
function Animal(name, txt) {
console.log('构造函数:Animal', this, name, txt)
this.type = '父类'
this.name = 'Animal_' + name;
this.txt = txt
}
Animal.prototype.getName = function () {
console.log('调用Animal原型上的方法:', this, this.name)
};
function Cat(name) {
console.log('构造函数:Cat', this, name)
this.name = 'Cat_' + name
const txt = '构造函数继承,先创造子类的实例对象this(例如:cat1,cat2),调用call后, 构造函数Animal中的this指向Cat的实例对象'
Animal.call(this, name, txt);
}
Cat.prototype = Object.create(Animal.prototype);
const cat2 = new Cat('2');
cat2.getName();
console.log(cat2.name);
ES6 class 继承
为什么子类的构造函数,一定要调用 super()?
原因:ES6的继承机制与ES5完全不同。
ES5的继承机制,是先创造一个独立的子类的实例对象,然后再将父类的方法添加到这个对象上面,即“实例在前,继承在后”。
ES6 的继承机制,则是先将父类的属性和方法,加到一个空的对象上面, 然后再将该对象作为子类的实例,即“继承在前,实例在后”。
这就是为什么ES6的继承必须先调用super()方法,因为这一步会生成一个继承父类的this对象,没有这一步就无法继承父类。
核心概念
- 私有的属性(#[prototyName])和方法(#[functionName])无能继承。
- 如果子类没有定义 constructor()方法,这个方法会默认添加,并且里面会调用 super()。也就是说,不管有没有显式定义,任何一个子类都有 constructor 方法。’
- 父类的静态属性和静态方法,也会被子类继承, 但是不能被实例继承。
- 第一种情况,super 作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次 super 函数。第二种情况,super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
class Person {
constructor(name) {
this.name = name;
}
static st_fn() {
console.log('静态方法不能被实例继承,可被子类继承')
}
say() {
console.log("say something:", this);
}
}
class Child extends Person {
constructor(name) {
super(name)
}
}
const person = new Person('父类');
Child.st_fn();