作为 JavaScript
中最重要的内容之一,继承问题一直是我们关注的重点。那么你是否清晰地知道它的原理以及各种实现方式呢
阅读这篇文章,你将知道:
这里默认你已经清楚的知道构造函数、实例和原型对象之间的关系,如果并不是那么清晰,那么推荐你先阅读这篇文章 -- JavaScript 中的原型与原型链
如果文章中有出现纰漏、错误之处,还请看到的小伙伴多多指教,先行谢过
以下↓
继承(inheritance)是面向对象软件技术当中的一个概念。如果一个类别
B
继承自
另一个类别A
,就把这个B
称为A的子类
,而把A
称为B的父类别
也可以称A是B的超类
。继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码 ...更多
通过这些概念和图示我们不难知道继承可以在我们的开发中带来的便捷,那么在 JavaScript
中如何去实现继承呢?
利用原型让一个引用类型继承另一个引用类型的属性和方法
function SuperType() {
this.name = ‘tt‘;
}
SuperType.prototype.sayName = function() {
return this.name
}
function SubType() {
this.name = ‘oo‘;
}
SubType.prototype = new SuperType()
var instance = new SubType()
instance.sayName() // oo
instance instanceof SubType // true
instance instanceof SuperType // ture
以上的试验中,我们创建了两个构造函数 SuperType
和 SubType
,并且让 SubType
的原型指向 SuperType
,SubType
也就继承了 SuperType
原型对象中的方法。所以在创建 instance
实例的时候,实例本身也就具有了 SuperType
中的方法,并且都处在它们的原型链中
SubType.prototype.constructor == SubType // false
SubType.prototype.constructor == SuperType // true
需要注意的是:这个时候 SubType.prototype.constructor
是指向 SuperType
的,相当于重写了 SubType
的原型对象。
用一张图表示:
SubType.prototype
相当于 SuperType
的实例存在的,所以 SubType.prototype.constructor
就指向 SuperType
优点:
缺点:
SubType
添加原型方法,就必须在 new SuperType
之后添加(会覆盖)在子类构造函数的内部调用超类型构造函数,通过
apply
和call
实现
function SuperType(name) {
this.name = name;
this.colors = [‘red‘, ‘orange‘, ‘black‘];
}
function SubType() {
SuperType.call(this, ‘tt‘);
}
var instance = new SubType()
var instance1 = new SubType()
instance.colors // [‘red‘, ‘orange‘, ‘black‘]
instance.name // tt
instance.colors.push(‘green‘);
instance.colors // [‘red‘, ‘orange‘, ‘black‘, ‘green‘]
instance1.colors // [‘red‘, ‘orange‘, ‘black‘]
优点:
call
可以指定不同的超类)缺点:
伪经典继承(最常用的继承模式):将原型链和借用构造函数的技术组合到一起。使用原型链实现对原型属性和方法的继承,通过构造函数来实现对实例属性的继承
function SuperType(name) {
this.name = name;
this.colors = [‘red‘, ‘orange‘, ‘black‘];
}
SuperType.prototype.sayName = function() {
return this.name
}
function SubType() {
SuperType.call(this, ‘tt‘);
this.name = ‘oo‘;
}
// 这里的 SubType.prototype.constructor 还是指向 SuperType
SubType.prototype = new SuperType();
var instance = new SubType();
var instance1 = new SubType();
instance.name // oo
instance.sayName() // oo
instance.colors.push(‘green‘);
instance.colors // [‘red‘, ‘orange‘, ‘black‘, ‘green‘]
instance1.colors // [‘red‘, ‘orange‘, ‘black‘]
优点:
缺点:
借助原型链可以基于已有的对象创建新对象,同时还不必因此创建自定义类型
function obj(o) {
function F(){}
F.prototype = o;
return new F();
}
var person = {
name: ‘tt‘,
age: 18,
colors: [‘red‘, ‘green‘]
}
var instance = obj(person);
var instance1 = obj(person);
instance.colors.push(‘black‘);
instance.name // tt
instance.colors // [‘red‘, ‘green‘, ‘black‘]
instance1.colors // [‘red‘, ‘green‘, ‘black‘]
创建一个临时的构造函数,然后将传入的对象当做这个构造函数的原型对象,最后返回这个临时构造函数的新实例。实际上,就是对传入的对象进行了一次浅复制
ES5
通过新增 Object.create()
规范化了原型式继承
更多 Object.create()语法请点击 这里
优点:
缺点: 和原型链继承基本一致,效率较低,内存占用高(因为要拷贝父类的属性)
创建一个仅用于封装继承过程的函数,在函数内部对这个对象进行改变,最后返回这个对象
function createAnother(obj) {
var clone = Object(obj);
clone.sayHi = function() {
alert(‘Hi‘);
}
return clone
}
var person = {
name: ‘tt‘,
age: 18,
friends: [‘oo‘, ‘aa‘, ‘cc‘],
sayName() {
return this.name
}
}
var instance = createAnother(person)
var instance1 = createAnother(person)
instance.friends.push(‘yy‘)
instance.name // ‘tt‘
instance.sayHi() // Hi
instance.friends // ["oo", "aa", "cc", "yy"]
instance1.friends // ["oo", "aa", "cc", "yy"]
优点:
缺点:
借用构造函数来继承属性,通过原型链的混成形式来继承方法。通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
function inherit(subType, superType) {
var obj = Object(superType.prototype); // 创建对象
obj.constructor = subType; // 指定constructor
subType.prototype = obj; // 指定对象
}
function SuperType(name) {
this.name = name;
this.colors = [‘red‘, ‘orange‘, ‘black‘];
}
SuperType.prototype.sayName = function() {
return this.name
}
function SubType() {
SuperType.call(this, ‘tt‘);
this.name = ‘oo‘;
}
inherit(SubType, SuperType)
var instance = new SubType()
instance.name // oo
instance.sayName // oo
instance instanceof SubType // true
instance instanceof SuperType // true
SubType.prototype.constructor == SubType // true
堪称完美,只是实现稍微复杂一点
作为 JavaScript
最重要的概念之一,对于继承实现的方式方法以及它们之间的差异我们还是很有必要了解的。
原文:https://www.cnblogs.com/ning123/p/11062269.html