手撸 JS 六大继承
前言
继承概念
:利用原型让一个引用类型继承另一个引用类型的属性和方法
函数都有一个 prototype 属性,该属性指向一个对象(这个对象指的是函数的原型对象)
举一个生活中的例子:先定义一个类(Class)叫汽车,汽车的属性包括颜色、轮胎、品牌、速度、排气量等,由汽车这个类可以派生出“轿车”和“货车”两个类,那么可以在汽车的基础属性上,为轿车添加一个后备厢、给货车添加一个大货箱。这样轿车和货车就是不一样的,但是二者都属于汽车这个类,这样从这个例子中就能详细说明汽车、轿车以及卡车之间的继承关系。 继承可以使得子类别具有父类的各种方法和属性,比如上面的例子中“轿车” 和 “货车” 分别继承了汽车的属性,而不需要再次在“轿车”中定义汽车已经有的属性。在“轿车”继承“汽车”的同时,也可以重新定义汽车的某些属性,并重写或覆盖某些属性和方法,使其获得与“汽车”这个父类不同的属性和方法。
1. 原型链继承
核心代码:SubType.prototype = new SuperType()
SuperType.prototype.getSuperValue = function() {
return this.property
}
// 父类
function SuperType() {
this.property = true
this.name = 'aa'
}
// 子类
function SubType() {
this.subproperty = false
}
`核心原理`: 将子类的原型赋值为父类的实例对象
SubType.prototype = new SuperType() // { property: true, __proto__: SuperType.prototype }
// SubType.prototype.getSuperValue = function() {
// return this.subproperty
// }
var instance = new SubType('xxx')
// instance:
// {
// subproperty: false,
// __proto__: {
// property: true,
// __proto__: SuperType.prototype
// }
// }
instance.getSuperValue() // true
var instance2 = new SubType()
1. 原型链继承 缺点:
- 原型实际上会变成另一个类型的实例,并且这个实例中的属性会被所有的子类实例所共享(改变了其中一个属性,则其他实例化对象上的属性也会对应发生改变)
- 在创建子类型的实例时,做不到向超类型的构造函数传参
2. 构造函数继承(经典继承)
核心代码:SuperType.call(this, name)
function SuperType(name) {
this.colors = ['red', 'green', 'blue']
this.people = ['a', 'b', 'c']
}
function SubType(name) {
SuperType.call(this, name)
}
var instance1 = new SubType()
instance1.colors.push('pink')
console.log(instance1.colors); // ['red', 'green', 'blue']
var instance2 = new SubType('小明')
console.log(instance2.colors);
2. 构造函数继承(经典继承)优点:
- 解决了原型链继承的两个缺点
构造函数继承(经典继承)缺点:
- 子类实例无法继承到超类构造函数原型上的属性和方法
- 所有的属性和方法都只能写在构造函数内部,降低了代码的复用性
3. 组合继承(伪经典继承)
核心代码:
- SuperType.call(this, name)
- SubType.prototype = new SuperType()
- SubType.prototype.constructor = SubType
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SuperType(name) {
this.name = name
this.colors = ['red', 'green', 'blue']
}
function SubType(name, age) {
SuperType.call(this, name)
this.age = age
}
SubType.prototype = new SuperType()
SubType.prototype.constructor = SubType
SubType.prototype.sayAge = function() {
console.log(this.age);
}
var instance1 = new SubType('小南', 20)
// console.log(instance1.colors); // ['red', 'green', 'blue']
instance1.sayName()
instance1.sayAge()
var instance2 = new SubType('小赖', 22)
instance2.sayName()
instance2.sayAge()
console.log(instance1 instanceof SubType);
3. 组合继承(伪经典继承)缺点:
- 超类构造函数无论何时,都要被调用两次
4. 原型式继承(单纯的对象之间继承可以胜任)
核心代码:var person1 = Object.create(person)
// 原型式继承
// function object(o) {
// function F() {}
// F.prototype = o
// return new F()
// }
// -----------------------------
var person = {
name: '小红',
colors: ['red', 'green', 'blue']
}
var person1 = Object.create(person, {
name: {
value: '小明'
}
})
var person2 = Object.create(person, {
name: {
value: '小王'
}
})
person1.colors.push('pink')
console.log(person1.name); // 小明
console.log(person2.name); // 小王
console.log(person1.colors); // [ 'red', 'green', 'blue', 'pink' ]
console.log(person2.colors); // [ 'red', 'green', 'blue', 'pink' ]
4. 原型式继承 缺点:
- 包含引用类型值的属性始终会共享
5. 寄生式继承
核心代码:var clone = Object.create(original) 函数 createPerson
// 寄生式继承
function createPerson(original) {
var clone = Object.create(original)
clone.sayGood = function() {
console.log('hello');
}
return clone
}
let obj = {
name: 'aaa'
}
let obj2 = createPerson(obj)
5. 寄生式继承 缺点:
- 做不到函数的复用`
6. 寄生组合式继承
核心代码:
- SuperType.call(this, name)
- SubType.prototype = Object.create(SuperType.prototype)
- SubType.prototype.constructor = SubType
// 寄生组合式继承
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SuperType(name) {
this.name = name
this.colors = ['red', 'green', 'blue']
}
function SubType(name, age) {
SuperType.call(this, name)
this.age = age
}
SubType.prototype = Object.create(SuperType.prototype)
SubType.prototype.constructor = SubType
SubType.prototype.sayAge = function() {
console.log(this.age);
}
var instance1 = new SubType('小南', 20)
instance1.colors.push('pink')
instance1.sayName() // 小南
instance1.sayAge() // 20
console.log(instance1.colors); // [ 'red', 'green', 'blue', 'pink' ]
var instance2 = new SubType('小赖', 22)
instance2.sayName() // 小赖
instance2.sayAge() // 22
console.log(instance2.colors); // [ 'red', 'green', 'blue' ]
目前来说应用最多的,相对而言,没有更好的解决方案,最优:寄生式组合继承
小编自制了一个 登录注册验证码,npm i 开箱即用,可以了解一下:给个 star 支持一下,谢谢~