前言:
JS里边的继承是工作中必用的,也是面试中必考的,所以这篇文章就给大家介绍一下每种继承的特点,希望对大家有所收获~!
原型链继承
//父类
function Person(name) {
this.name = name || 'hpp';
this.sayName = function() {
return this.name;
}
}
//子类
function Son() {
this.age = 22;
}
Son.prototype = new Person();
var p = new Son();
console.log(p.name + p.age + p.sayName()) // hpp 22 hpp
var p1 = new Per();
//修改父类对象的属性
p1.__proto__.name= 'wjf';
console.log(p.name + p1.name); // wjf wjf
- 关键点:让 Son构造函数的 prototype 属性 指向 一个 Person构造函数的实例!
- 特点:
-
- 继承实例构造函数的属性和方法
- 继承父类构造函数的属性和方法
- 缺点:
-
- 实例无法向父类构造函数传参数
- 单一继承,只能有一个父类
- 所有实例对象都共享父类的属性和方法,会导致一个实例修改父类属性,其余实例的父类属性都被修改!
借用构造函数继承:
function Person(name) {
this.name = name || 'hpp';
this.sayName = function() {
return this.name;
}
}
function Man(){
this.sex = '男';
this.saySex = function(){
return this.sex;
}
}
function Per() {
Person.apply(this,['wjf'])
Man.call(this)
this.age = 22;
}
var p = new Per();
console.dir(p)
- 关键点:使用 call 和 apply 方法将父类的构造函数引入子类里边
- 特点:
-
- 继承父类构造函数的属性和方法
- 实例可以向父类构造函数传递参数
- 可以继承多个父类
- 缺点:
-
- 只能继承父类构造函数的属性
- 无法实现构造函数的复用
- 每个实例都有父类构造函数的副本
组合继承(原型链继承 + 构造函数继承)
function Person(name) {
this.name = name || 'hpp';
this.sex = sex || 'man'
}
Person.prototype.sayInfo = function() {
return this.name + this.sex;
}
function Per() {
Person.apply(this, ['wjf', 'man'])
this.age = 22;
}
Per.prototype = new Person();
Per.prototype.constructor = Per;
var p = new Per();
p.sayInfo()
console.dir(p)
- 关键点;
-
- 子类继承父类的属性
- 父类的公共方法放到 prototype 上边,实现多个 实例共享
- 缺点:
-
- 调用了两次父类
- 优点:
-
- 每个实例都有自己的属性,同时可以共享公共的方法
原型式继承:
function Person(name) {
this.name = name || 'hpp';
this.colors = [];
}
function Per(obj) {
function F(){};
F.prototype = obj;
return new F();
}
var p = new Person();
var pp = Per(p);
- 关键点:
-
- 用一个函数包装一个对象,然后返回这个函数的调用,object.create()就是这个原理,浅复制对象
- 特点:
-
- 包装对象
- 缺点:
-
- 原型的引用类型属性会在各实例之间共享
寄生式继承
function Person(name) {
this.name = name || 'hpp';
this.colors = [];
}
function Object(obj) {
function F(){};
F.prototype = obj;
return new F();
}
function CreateAnother(original){
var clone = Object(original);
clone.sayHi = function(){
console.log('hi');
}
return clone;
}
var p = new Person();
var pp = CreateAnother(p);
pp.sayHi();
- 关键点:
-
- 创建一个用于封装继承过程的函数,这个函数可以在内部以某种方式增强对象,然后返回包装好的对象
- 缺点:
-
- 使用寄生方式为对象添加函数,无法做到复用
寄生组合式继承
function Person(name) {
this.name = name || 'hpp';
this.colors = [];
}
function Object(obj) {
function F(){};
F.prototype = obj;
return new F();
}
function CreateAnother(son,father){//寄生的关键,封装一个函数过程,用于增强对象
var clone = Object(father);
clone.constructor = son;
son.prototype = clone;
}
function Boy(name,age){
Person.call(this,name)//借用构造函数
this.age=age;
}
Boy.prototype.sayMyInfo = function(){
console.log(this.name,this.age);
}
var p = new Person();
var pp = new Boy('wjf',22);
CreateAnother(pp,p);
pp.sayMyInfo();
- 特点:
-
- 只调用了一次父类构造函数,避免了在子类的prototype上边创建爱你不必要的属性。
- 保持了原型链不变
- 正常使用 instanceof 和 isProtytypeOf() 方法
感谢大家阅读,如有任何问题,请评论区回复即可!