字数
1448 字
阅读时间
7 分钟
原型链继承
将父类的实例作为子类的原型
js
function Parent() {
this.isShow = true
this.info = {
name: "yhd",
age: 18,
};
}
Parent.prototype.getInfo = function() {
console.log(this.info);
console.log(this.isShow); // true
}
function Child() {};
Child.prototype = new Parent();
let Child1 = new Child();
Child1.info.gender = "男";
Child1.getInfo(); // {name: "yhd", age: 18, gender: "男"}
let child2 = new Child();
child2.getInfo(); // {name: "yhd", age: 18, gender: "男"}
child2.isShow = false
console.log(child2.isShow); // false优点:
- 父类方法可以复用
缺点: - 父类的所有
引用属性会被子类共享,更改一个子类的引用属性,会导致其他子类的引用属性一同更改 - 子类实例不能给父类构造函数传参
(盗用) 构造函数继承
在子类中调用父类的构造函数的同时,通过 apply 和 call 绑定作用域
js
function Parent(name) {
this.info = { name: name };
}
function Child(name) {
//继承自Parent,并传参
Parent.call(this, name);
//实例属性
this.age = 18
}
let child1 = new Child("yhd");
console.log(child1.info.name); // "yhd"
console.log(child1.age); // 18
let child2 = new Child("wxb");
console.log(child2.info.name); // "wxb"
console.log(child2.age); // 18优点:
- 可以在子类构造函数中向父类传参
- 父类的引用类型不会被共享
缺点: - 子类不能访问父类原型上定义的方法,即父类
Parent.prototype上的方法
组合继承
结合原型链继承和构造函数继承
js
function Parent(name) {
this.name = name
this.colors = ["red", "blue", "yellow"]
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Child(name, age) {
// 继承父类属性
Parent.call(this, name)
this.age = age;
}
// 继承父类方法
Child.prototype = new Parent();
Child.prototype.sayAge = function () {
console.log(this.age);
}
let child1 = new Child("yhd", 19);
child1.colors.push("pink");
console.log(child1.colors); // ["red", "blue", "yellow", "pink"]
child1.sayAge(); // 19
child1.sayName(); // "yhd"
let child2 = new Child("wxb", 30);
console.log(child2.colors); // ["red", "blue", "yellow"]
child2.sayAge(); // 30
child2.sayName(); // "wxb"优点:
- 父类的方法可以复用
- 可以在 Child 构造函数中向 Parent 构造函数中传参
- 父类构造函数中的引用属性不会被共享
原型继承
对参数对象的一种浅复制 —— Object.create()
js
function objectCopy(obj) {
function Fun() { };
Fun.prototype = obj;
return new Fun()
}
let person = {
name: "yhd",
age: 18,
friends: ["jack", "tom", "rose"],
sayName:function() {
console.log(this.name);
}
}
let person1 = objectCopy(person);
person1.name = "wxb";
person1.friends.push("lily");
person1.sayName(); // wxb
let person2 = objectCopy(person);
person2.name = "gsr";
person2.friends.push("kobe");
person2.sayName(); // "gsr"
console.log(person.friends); // ["jack", "tom", "rose", "lily", "kobe"]优点:
- 父类方法可复用
缺点: - 父类的引用会被所有子类所共享
- 子类实例不能向父类传参
寄生式继承
在原型式继承上进行改造
js
function objectCopy(obj) {
function Fun() { };
Fun.prototype = obj;
return new Fun();
}
function createAnother(original) {
let clone = objectCopy(original);
clone.getName = function () {
console.log(this.name);
};
return clone;
}
let person = {
name: "yhd",
friends: ["rose", "tom", "jack"]
}
let person1 = createAnother(person);
person1.friends.push("lily");
console.log(person1.friends);
person1.getName(); // yhd
let person2 = createAnother(person);
console.log(person2.friends); // ["rose", "tom", "jack", "lily"]寄生组合继承

js
function objectCopy(obj) {
function Fun() { };
Fun.prototype = obj;
return new Fun();
}
function inheritPrototype(child, parent) {
let prototype = objectCopy(parent.prototype); // 创建对象
prototype.constructor = child; // 增强对象
Child.prototype = prototype; // 赋值对象
}
function Parent(name) {
this.name = name;
this.friends = ["rose", "lily", "tom"]
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
inheritPrototype(Child, Parent);
Child.prototype.sayAge = function () {
console.log(this.age);
}
let child1 = new Child("yhd", 23);
child1.sayAge(); // 23
child1.sayName(); // yhd
child1.friends.push("jack");
console.log(child1.friends); // ["rose", "lily", "tom", "jack"]
let child2 = new Child("yl", 22)
child2.sayAge(); // 22
child2.sayName(); // yl
console.log(child2.friends); // ["rose", "lily", "tom"]优点:
- 只调用一次父类构造函数
- Child 可以向 Parent 传参
- 父类方法可以复用
- 父类的引用属性不会被共享
与 extends 继承区别
语法差异:
- 寄生组合继承:寄生组合继承是一种通过组合构造函数继承和原型链继承的方式来实现继承。在代码中,你需要手动编写继承的逻辑,包括借用构造函数继承和设置原型链。
- ES6 中的
extends:ES6 引入了extends关键字,使得继承变得更加直观和简洁。你可以通过class和extends关键字来声明一个类,并直接继承另一个类,不需要手动编写继承逻辑。
语法使用:
- 寄生组合继承:使用寄生组合继承时,你需要手动创建构造函数、调用父类构造函数、设置原型链等步骤。通常需要创建一个中间函数来实现继承。
- ES6 中的
extends:使用 ES6 中的extends关键字,你只需要声明一个类,并使用extends关键字指定父类,就可以直接继承父类的属性和方法,更加简洁。
对
super()的处理:- 寄生组合继承:在寄生组合继承中,需要手动调用父类的构造函数来设置继承的属性,通常通过在子类构造函数中使用
Parent.call(this, ...args)来实现。 - ES6 中的
extends:在 ES6 中,使用extends关键字继承的子类,会自动调用父类的构造函数,不需要手动处理。在子类的构造函数中,使用super(...args)来调用父类的构造函数,以初始化父类的属性。
- 寄生组合继承:在寄生组合继承中,需要手动调用父类的构造函数来设置继承的属性,通常通过在子类构造函数中使用
兼容性:
- 寄生组合继承:寄生组合继承是一种在 ES5 中实现继承的方式,兼容性较好,可以在大多数浏览器中运行。
- ES6 中的
extends:ES6 中的extends关键字是一种新的语法糖,需要支持 ES6 的运行环境才能使用,不支持 ES6 的浏览器可能会报错
参考
JS继承 原型链继承、构造函数继承、组合继承、原型继承、寄生式继承、寄生组合继承 - 掘金
图解JS中的六种继承:原型链、盗用构造函数、组合继承、原型式继承、寄生继承、组合寄生继承 - 掘金