js中的继承就是让子类能够访问父类的属性和方法。
1. 原型链继承
原型链继承就是让子类的原型指向父类的实例,借助原型链的查找规则,让子类能够查找到父类身上。
Parent.prototype.say = function () {
console.log('hello');
}
function Parent() { // 形参age
this.name = 'parent';
this.age = 50 // this.age = age,这样子类就无法给父类传值了
}
// 原型链继承
Child.prototype = new Parent(); // {name: 'parent', age: 50}.__proto__ === Parent.prototype
function Child() {
this.name = 'child';
}
const c = new Child();
console.log(c.name);
console.log(c.age);
c.say();
但是不能子类无法给父类传值。
2. 构造函数继承
在子类调用父类构造函数,这样就可以继承父类的属性和方法。但是无法继承父类的原型。
Parent.prototype.say = function () {
console.log('hello');
}
function Parent(age) {
this.name = 'parent';
this.age = age
}
function Child(name, age) {
// 父类构造函数
Parent.call(this, age); // 让 Parent 里面的 this 指到 Child 身上
this.name = name;
}
const c = new Child('child', 50);
console.log(c.name);
console.log(c.age);
c.say(); // 报错,无法继承父类的原型
3. 组合继承
就是将原型链继承与构造函数继承结合起来。但是父类构造函数执行了两次
Parent.prototype.say = function () {
console.log('hello');
}
function Parent(age) {
this.name = 'parent';
this.age = age
}
// 原型链继承
Child.prototype = new Parent();
function Child(name, age) {
// 构造函数
Parent.call(this, age); // 让 Parent 里面的 this 指到 Child 身上
this.name = name;
}
const c = new Child('child', 50);
console.log(c.name);
console.log(c.age);
c.say();
4. 原型式继承
Object.create(obj)
就是创建一个对象,让该对象的隐式原型指向obj,如newObj = Object.create(obj)
,newObj的隐式原型就是obj。这样就可以实现继承。
const obj = {
a: 1,
b: 2,
c: 3
}
let newObj = Object.create(obj) // newObj.__proto__ = obj
console.log(newObj); // {}
console.log(newObj.a); // 1
5. 寄生组合式继承
使用Object.create(Parent.prototype)
创建一个空对象,让这个对象的隐式原型等于Parent.prototype,然后将该对象赋值给Child的显示原型。也就是Child.prototype.__proto__ = Parent.prototype
。
Parent.prototype.say = function () {
console.log('hello');
}
function Parent(age) { // 相当于Parent =new Function
this.name = 'parent';
this.age = age
}
// 创建一个空对象,让这个对象的隐式原型等于Parent.prototype,然后将该对象赋值给Child的显示原型
// Child.prototype.__proto__ = Parent.prototype
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child; // 让 Child 继承 Parent 上的 constructor
function Child(name, age) {
Parent.call(this, age); // 继承 Parent 的属性和方法
this.name = name;
}
const c = new Child('child', 50);
console.log(c.name);
console.log(c.age);
c.say();
console.log(c.constructor); // 表示 c 对象是由谁创建的,是Child.prototype身上的
其中c.constructor
表示 c 对象是由谁创建的,是Child.prototype身上的,所以如果不加Child.prototype.constructor = Child;
就会导致c对象是由Parent创建的。
也就是本来Child.prototype.constructor = Child
,但是后面Child.prototype
又重新赋值为一个空对象,后面再访问就访问不到了,但是由于Child.prototype.__proto__=Parent.prototype
,也就是这个空对象有个隐式原型,会顺着隐式原型向上访问,访问到Parent.prototype
身上去了。
6. class继承: extends + super()
在es6,添加了class继承(extends + super()),使得继承更加直观优雅。
class Parent {
constructor(name, age) {
this.name = name
this.age = age
}
// 相当于定义在class类的原型上
say() {
console.log('hello');
}
}
class Child extends Parent {
constructor(sex, name, age) {
super(name, age)
this.sex = sex
}
}
const c = new Child('男', '张三', 18)
console.log(c); // Child { name: '张三', age: 18, sex: '男' }
c.say() // hello