我们可以简单的分为以下几种继承方式:
- 原型链继承
- 构造函数继承
- 组合继承
- 寄生组合继承/加强版寄生组合继承
- 类继承
以下 A代表父级 B代表子级
我们先看原型链继承
先上代码
function A(name,age){
this.name = name;
this.arr = [];
this.age = age;
this.sing = function(){
return '我会唱歌、我会跳舞。'
}
}
function B(run){
this.run = run
}
B.prototype = new A('zjq',18)
let a = new B('123')
let b = new B('456')
a.arr.push('1')
console.log(b.arr) //['1']
B已经完全的集成到了A的属性和方法,但是有一个缺点就是当我们实例化两个B的时候,给第一个arr添加item,第二个实例化对象也会跟着变化。a和b的arr都新添了一个item。方法变成了共享,不是实例所私有的。(引用类型)
构造函数继承
上代码
function A(name,age){
this.name = name;
this.age = age;
this.arr =[];
this.sing = function(){
return '我会唱歌、我会跳舞。'
}
}
A.prototype.zjq = function(){
return 'run'
}
function B(run){
this.run = run
A.call(this,'zjq',this.run) //父级的属性和方法称为子级的私有属性和方法 子级可以向父级传参
}
let Bobj = new B('runing')
console.log(Bobj)
console.log(Bobj.sing())
let a = new B('123')
let b = new B('456')
a.arr.push('1')
console.log(b.arr) //[]
构造函数继承虽然可以使用A中的方法和属性,但是不是继承的关系过来的,它的_proto_上没有A的任何信息,它将A的属性和方法变成了自己的属性和方法,但是原型链上的方法(zjq方法并没有)是无法继承到的。创建子类实例,可以向父类构造函数传参数。解决了方法变成了共享的问题,变成了实例所私有的。
组合继承
上代码
function A(name, age) {
this.name = name;
this.age = age;
this.arr=[]
}
A.prototype.sing = function () {
return '我会唱歌、我会跳舞。' + this.name + this.age
}
function B(run) {
this.run = run
A.call(this, 'zjq', this.run) //父级的属性和方法称为子级的私有属性和方法 子级可以向父级传参
}
B.prototype = new A()
let brr = new B('参数')
let a = new B('123')
let b = new B('456')
a.arr.push('1')
console.log(b.arr) //[]
console.log(brr)
console.log(brr.sing())
console.log(brr.age)
结合原型链继承和借用构造函数继承的优点 ,继承了A的属性和方法也可以向A传递自己的参数。解决了方法变成了共享的问题,变成了实例所私有的,但是A构造函数被调用了两次。
寄生组合继承
上代码
function A(name, age) {
this.name = name;
this.age = age;
this.arr = []
}
A.prototype.sing = function () {
return '我会唱歌、我会跳舞。' + this.name + this.age
}
function B(run) {
this.run = run
A.call(this, 'zjq', this.run)
}
B.prototype = A.prototype
// let b= new B('123')
// console.log(b)
B.prototype.sing = function () {
return 'xxx'
}
let a = new B('123')
let b = new B('456')
a.arr.push('1')
console.log(b.arr) //[]
console.log(new A().sing()) //变成了xxx 而不是 return '我会唱歌、我会跳舞。' + this.name + this.age
解决了方法变成了共享的问题,变成了实例所私有的,但是又有一个突出的问题,B可以改变原型链上的东西,A和B共享了原型链。
加强版寄生组合继承
function A(name, age) {
this.name = name;
this.age = age;
}
A.prototype.sing = function () {
return '我会唱歌、我会跳舞。' + this.name + this.age
}
function B(run) {
this.run = run
A.call(this, 'zjq', this.run)
}
function f(){
}
f.prototype = A.prototype
B.prototype = new f()
//上面三行代码可以用Object.create()实现 //创建了以A.prototype为原型的实例对象
//B.prototype= Object.create(A.prototype) 相当于开辟了一个新的对象 这个对象的原型指向A的prototype
let b= new B('123')
//这样一来b的__proto__上就没有sing方法,在__proto__的__proto__上存在sing方法(指向A)
/*
这样一来 在B的prototype上加sing属性 就影响不到A了
__proto__: A
sing: ƒ ()
__proto__:
sing: ƒ ()
constructor: ƒ A(name)
__proto__: Object
*/
console.log(b)
B.prototype.sing = function(){
return 'xxx'
}
console.log(new A().sing()) //return '我会唱歌、我会跳舞。' + this.name + this.age
解决了共享原型链的问题。 完美收官。
类继承
上代码
class A {
//父级构造函数
constructor(name) {
this.name = name;
}
sing() {
return this.name + 'xxx'
}
}
class B extends A {
//子级继承父级
constructor(name,age) {
super(name) 调用实现父类的构造函数 并传递参数
this.age = age
}
}
let b = new B(12333,222) //实例化子级
console.log(b)
console.log(b.sing()) //return this.name + 'xxx'
原型链继承继承prototype方法
构造函数继承继承属性和属性方法
以上内容有不对的还请大佬及时评论。