前言
两天没写了,靠,怎么这么懒,废话不多说,来了来了。
继承
子类能够享有父类所拥有的属性和方法,在创建类似实例的时候非常有用。
原型链继承
不知道大家有没有搞清楚构造函数、实例对象、原型对象之间的关系,其实构造函数也是一个对象,js一切皆对象嘛,function也是通过new Function()来创建的,而且
Function.prototype.__proto__ === Object.prototype
。
我想说的是:每个实例对象都是通过__proto__
指针来与其构造函数的原型对象进行关联的,访问属性时就是按照这条原型链。
第一种继承:简单的获取到父类的属性和方法
function Parent(name) {
this.name = name || 'parentName';
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Son(age) {
this.age = age;
}
Son.prototype = new Parent();
const son1 = new Son(18);
- 原理:
instance.__proto__ == constructor.prototype;
上面说的关系链 - 缺点:
- 所有实例共享父类的属性和方法,一旦子类修改自身prototype的 属性,其他子类也会受到影响
- 只能继承一个父类
- 子类在创建实例的时候无法向父类传参
- 子类想要添加自己的原型方法和属性必须在继承之前操作
借用构造函数继承
子类在创建实例时可以传递参数给父类
function Parent(name) {
this.name = name || 'parentName';
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Son(name, age) {
Parent.call(this, name);
this.age = age;
}
son1 = new Son("carter", 18);
- 原理:
call方法执行父类的方法,添加父类本身属性给子类 - 缺点:
- 每个子类实例都需要调用父类构造函数
- 无法继承父类的原型中的属性和方法
- 并不属于父类的实例,只属于子类
原型加借用构造函数继承
前面两种方法的综合,借助原型链继承父类的原型属性和方法,借用构造函数(可以传参),继承父类的属性和方法,不存在共享属性的问题。
function Parent(name) {
this.name = name || 'parentName';
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Son(name, age) {
Parent.call(this, name);
this.age = age;
}
Son.prototype = new Parent();
son1 = new Son("carter", 18);
缺点:
- 需要调用两次构造函数
- 需要重写子类原型的constructor属性
组合式继承
遇上述方法不同的是,在继承原型属性时,直接将子类原型对象指向父类的原型对象,这样就不需要调用两次构造函数了。
function Parent(name) {
this.name = name || 'parentName';
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Son(name, age) {
Parent.call(this, name);
this.age = age;
}
Son.prototype = Parent.prototype;
son1 = new Son("carter", 18);
缺点:
- 子类实例的constructor属性指向不对
寄生式组合继承
与组合式继承不同的是,在继承原型属性时,完全复制一个父类的原型对象指向子类原型。重写constructor。
function Parent(name) {
this.name = name || 'parentName';
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Son(name, age) {
Parent.call(this, name);
this.age = age;
}
Son.prototype = Object.create(Parent.prototype);
Son.prototype.constructor = Son;
// Object.create原理:
// Object.create = function (protoObj) {
// function F() {};
// F.prototype = protoObj;
// return new F();
// }
son1 = new Son("carter", 18);
ES6的class继承
class Parent {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class Son extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
}
son1 = new Son("carter", 18);
总结
ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。
网友评论