作为初学者,结合了自己最近所学,记录下继承的几种方式,如果有错,请指导,如有侵权,请告知,谢谢!
继承继承,就有父类
function Father(name, age) {
this.name = name; this.age = age; //实力属性
this.sayHi = () => { console.log(this.name + '今年' + this.age + '岁了') } //实力方法
};
//原型方法
Father.prototype.sayMe = `我是$2104班级`;
Father.prototype.eat = (food) => { console.log("我爱吃" + food) };
// 后台检测
// let fat = new Father('Joy', 14);
// console.log(fat, fat.sayMe)
// fat.sayHi();
// fat.eat('玉米')
// console.log(fat instanceof Father); //true
继承方法1(原型链继承)
(将父类的实例作为子类的原型)
function Child() { };
Child.prototype = new Father();
Child.prototype.name = "Tom";
Child.prototype.age = 18;
let child = new Child("Boy",18); //Boy,18无法实现传参
console.log(child, child.sayMe);
child.sayHi();
child.eat(); //我爱吃undefined
child.eat('桃子');
console.log(child instanceof Father); //true
console.log(child instanceof Child); //true
// 特点:非常单纯的继承关系,实例是子类的实例,也是父类的实例;父亲新增的属性,子类都能访问;简单
// 缺点:为子类添加属性或方法,要在new语句后执行,不能放在构造器中;无法实现多继承;创建子类实例,无法向父类传参
继承方法2(构造函数继承)复制父类的实例属性给子类,没有原型)
function Child(name, age) {
Father.apply(this, arguments);
// this.name = name || "Lucy";
// this.age = age || 15;
};
let child = new Child('Jack', 14); //可以传参,如果没传参用内置的参数
// let child = new Child();
console.log(child);
console.log(child.sayMe); //undefined
child.sayHi();
// child.eat(); //报错
child.eat('西瓜');
console.log(child instanceof Father); //false
console.log(child instanceof Child); //true
// 特点:解决子类实例共享父类引用属性的问题;创建子类时;可以向父类传递参数;可以实现多继承
// 缺点:实例是父类的不是子类的实例;只能继承实例的属性、方法不能继承原型的;每个子类都有父类的实例的函数副本,影响性能
继承方法3(实例继承)为父类添加新特性,作为子类实例返回)
function Child(name, age) {
let F = new Father();
F.name = name || "Lucy";
F.age = age || 15;
return F;
};
let child = new Child('Bob', 19);
console.log(child);
console.log(child.sayMe);
child.sayHi();
child.eat('西瓜');
console.log(child instanceof Father); //true
console.log(child instanceof Child); //false
// 特点:不限制调用方法,不管是new Child() 还是 子类(),返回的对象具有相同的效果
// 缺点:实例是父类的实例,不是子类的实例
// 继承方法4(拷贝继承)
function Child() {
Father.apply(this, arguments);
let F = new Father();
for (let a in F) {
Child.prototype[a] = F[a];
};
};
let child = new Child('Xicy', 20);
console.log(child);
console.log(child.sayMe);
child.sayHi();
child.eat('西瓜');
console.log(child instanceof Father); //false
console.log(child instanceof Child); //true
// 特点:支持多继承
// 缺点:效率较低,占用内存多,无法获取父类不可枚举的属性或方法(有的不可枚举方法,无法用forin访问到)
// 继承方法5(组合继承)(通过调用父类构造,继承父类的属性并保留传参的优势,然后通过父类的实例作为子类的原型,实现服用)
function Child(name,age) {
Father.apply(this, arguments);
// this.name = name || "Lucy";
//this.age = age || 15;
};
Child.prototype = new Father();
Child.prototype.constructor = Child;
let child = new Child('Reg', 175);
// let child = new Child();
console.log(child);
console.log(child.sayMe);
child.sayHi();
child.eat('西瓜');
console.log(child instanceof Father); //true
console.log(child instanceof Child); //true
// 特点:弥补了构造继承的求点,不存在属性共存的问题,可传参,可复用
// 缺点:调用了2次父类的构造,生成了2份实例
// 继承方法6(原型式继承)
function inherite(father) {
const F = function () { };
F.prototype = father;
F.prototype.constructor = F;
return new F();
};
let father = new Father('Taken', 20);
let child = inherite(father);
console.log(child);
console.log(child.sayMe);
child.sayHi();
child.eat('西瓜');
console.log(child instanceof Father); //true
console.log(child instanceof inherite); //false
//用一个函数包装一个对象,然后返回这个函数的调用。 Object.create()就是这个原理
继承方法7(寄生继承)(通过寄生方式,砍掉了父类的实例属性,这样,在调用2次父类的构造,就不会初始化2次实例的属性、方法)
function inherite(child, father) {
const F = function () { };
F.prototype = father.prototype;
child.prototype = new F();
child.prototype.constructor = child;
};
function Child(name, age) {
Father.apply(this, arguments);
this.name = name || "Lucy";
this.age = age || 15;
};
inherite(Child, Father)
// let child = new Child('Date', 75);
let child = new Child();
console.log(child);
console.log(child.sayMe);
child.sayHi();
child.eat('苦瓜');
console.log(child instanceof Father); //true
console.log(child instanceof Child); //true
// 特点:缺点几乎没有
// 缺点:过程比较复杂