原型链继承
实现方法: 将子类的原型对象关联到父类的实例对象当中Children.prototype = new Parent();
优点: 实现了继承,并且子类可以共享父类原型上的属性和方法,
缺点: 但是引用类型的属性被所有实例共享存在安全问题 , 而且在创建子类实例的时候, 不能向 parent 当中传参,只能使用定义好的属性和方法。
//原型链继承
function Parent() {
this.collection = ['ryan', 'mike'];
}
Parent.prototype.eating = function () {
console.log(this.name + 'is eating');
};
function Children(name) {
this.name = name;
}
// 关键代码
Children.prototype = new Parent();
const child_1 = new Children('clc');
child_1.eating(); // clc在吃饭;
借用构造函数继承
实现方法: 在子类构造函数当中用 call 调用父类构造函 Parent.call(this,参数)
优点:避免了引用类型属性被实例共享的安全问题,并且也做到了可以向 parent 当中传递参数
缺点:但是缺点就是方法在构造函数当中定义, 没有利用原型, 每创建一个实例就会创建一遍方法
// 借用构造函数继承
function Parent(name, age) {
this.name = name;
this.age = age;
this.collection = ['ryan', 'mike'];
this.eating = function () {
console.log(this.name + 'is eating');
};
}
function chilren(name, age) {
Parent.call(this, name, age);
}
const child_1 = new Children('clc', 18);
组合继承
- 实现方法:将原型链继承和借用构造函数结合起来。
- 优点:融合原型链继承和构造函数的优点(既可以传递参数调用父构造函数,又可以继承父构造函数原型上的方法,避免了引用类型属性被实例共享),
- 缺点:缺点是存在效率问题, 父构造函数会调用两次,导致子类实例和原型上存在同名属性。
function Parent(name, age) {
this.name = name;
this.age = age;
this.collection = ['ryan', 'mike'];
}
Parent.prototype.eating = function () {
console.log(this.name + 'is eating');
};
// 关键代码
function Children() {
Parent.call(this, name, age);
}
Children.prototype = new Parent();
const child_1 = new Children();
原型式继承
- 实现思路:就是规范化的 Object.create(o)返回一个对象, 这个对象的原型是 o,
__proto__指向 o。 - 适用于你有一个对象在他的基础上再创建一个对象
function myObjectCreate(o) {
function F() {}
F.prototype = o;
return new F();
}
// 等同于 object.create(o)
寄生式继承
- 实现思路:在原型式继承的基础上以某种方式增强对象, 最后返回对象
- 缺点: 在该对象上添加的方法难以重用。
// 寄生式继承
function jicheng(o) {
const clone = myObjectCreate(o);
clone.sayHi = function () {
console.log('你好');
};
return clone;
}
寄生式组合继承
- 实现方式:通过寄生式继承来增强子类原型对象。和原型式类比,不直接将父类的实例关联到子类的原型对象上,而是将一个父类原型对象,通过Object.create()关联到子类的原型对象上。
- 最佳实践,不会像组合继承那样调用两次父构造函数,也不会像原型链继承那样在继承的时候会共享父类引用类型的属性,并且既可以向父类构造函数传递参数,又可以通过原型对象来共享属性和方法。
// 寄生式组合继承
function myObjectCreate(o) {
function F() {}
F.prototype = o;
return new F();
}
function inherit(son, parent) {
son.prototype = myObjectCreate(parent.prototype);
Object.defineProperty(son.prototype, 'constructor', {
enumerable: false,
configurable: true,
writable: true,
value: son,
});
}
类继承
类是构造函数和原型的语法糖,babel在进行编译的时候,也是将类编译成了构造函数,extends关键字被编译为寄生组合式继承。
类继承的babel编译流程是怎么样的。最核心的就是super,为什么每一次继承前,都要先super调用父类构造函数?因为一般的继承都是先创建子类的实例,在通过继承的手段去调用父类的构造函数。
而类在编译的时候是通过Reflect.constructro()这个方法,是通过先调用父类构造函数来创建出子类的实例对象。所以我们每次先super一下,才能拿到子类的实例对象,这也是为什么this要放在super之后进行调用。
var Student = /*#__PURE__*/ (function (_Person) {
// 实现之前的寄生式继承的方法(静态方法的继承)
_inherits(Student, _Person);
var _super = _createSuper(Student);
function Student(name, age, sno) {
var _this;
_classCallCheck(this, Student);
// Person不能被当成一个函数去调用
// Person.call(this, name, age)
debugger;
// 创建出来的对象 {name: , age: }
_this = _super.call(this, name, age);
_this.sno = sno;
// {name: , age:, sno: }
return _this;
}
_createClass(Student, [
{
key: "studying",
value: function studying() {
console.log(this.name + " studying~");
},
},
]);
return Student;
})(Person);
var stu = new Student();