继承的方法和优缺点
原型链继承
实现方式:将子类的原型链指向父类的对象实例
原理:
- 子类实例
child
的__proto__
指向Child
的原型链prototype
Child.prototype
指向Parent
类的对象实例- 该父类对象实例的
__proto__
指向Parent.prototype
- 所以
Child
可继承Parent
的构造函数属性、方法和原型链属性、方法
优点:
- 可继承构造函数的属性,父类构造函数的属性,父类原型的属性
- 简单易懂,易于实现。
缺点:
- 所有子类实例共享父类的引用属性,修改一个实例的引用属性会影响其他实例。
- 无法向父类构造函数传递参数。
js
function Parent() {
this.name = "Parent";
}
function Child() {
this.age = 18;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
const child = new Child();
console.log(child.name); // 输出 'Parent'
console.log(child.age); // 输出 18
构造函数继承
实现方式:在子类构造函数中使用call
或者apply
劫持父类构造函数方法,并传入参数
原理:使用call
或者apply
更改子类函数的作用域,使 this 执行父类构造函数,子类因此可以继承父类共有属性
优点:可解决原型链继承的缺点
缺点:不可继承父类的原型链方法,构造函数不可复用
js
function Parent(name, id) {
this.id = id;
this.name = name;
this.printName = function () {
console.log(this.name);
};
}
Parent.prototype.sayName = function () {
console.log(this.name);
};
function Child(name, id) {
Parent.call(this, name, id);
// Parent.apply(this, arguments);
}
var child = new Child("jin", "1");
child.printName(); // jin
child.sayName(); // Error
组合继承
原理:综合使用构造函数继承和原型链继承
优点:可继承父类原型上的属性,且可传参;每个新实例引入的构造函数是私有的
缺点:会执行两次父类的构造函数,消耗较大内存,子类的构造函数会代替原型上的那个父类构造函数
js
function Parent(name, id) {
this.id = id;
this.name = name;
this.list = ["a"];
this.printName = function () {
console.log(this.name);
};
}
Parent.prototype.sayName = function () {
console.log(this.name);
};
function Child(name, id) {
Parent.call(this, name, id); //第一次调用
// Parent.apply(this, arguments);
}
Child.prototype = new Parent(); //第二次调用
var child = new Child("jin", "1");
child.printName(); // jin
child.sayName(); // jin
var a = new Child();
var b = new Child();
a.list.push("b");
console.log(b.list); // ['a']
原型式继承
原理:类似Object.create
,用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象,结果是将子对象的__proto__
指向父对象
缺点:共享引用类型
js
var parent = {
names: ["a"],
};
function copy(object) {
function F() {}
F.prototype = object;
return new F();
}
var child = copy(parent);
寄生式继承
原理:二次封装原型式继承,并拓展 优点:可添加新的属性和方法
js
function createObject(obj) {
var o = copy(obj);
o.getNames = function () {
console.log(this.names);
return this.names;
};
return o;
}
寄生组合式继承
原理:改进组合继承,利用寄生式继承的思想继承原型
优点:
- 只调用一次父类构造函数
- 继承父类原型链上的方法
js
function Parent(name) {
this.name = name;
}
Parent.prototype.sayHello = function () {
console.log("Hello, " + this.name);
};
function Child(name, age) {
Parent.call(this, name); // 只调用一次父类构造函数
this.age = age;
}
// 使用 Object.create 创建一个新的对象,并将其原型设置为 Parent.prototype
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const child = new Child("Alice", 18);
child.sayHello(); // 输出 'Hello, Alice'