繼承簡單來講就是使子類擁有父類的屬性和方法,而不須要重複編寫相同的代碼.前端
舉個例子,飛機有客運機和戰鬥機,這兩種機型的共有屬性是顏色,公有方法是起飛,可是客運機的承載的是乘客,而戰鬥機承載的是子彈,它還有一個功能是射擊.咱們就能夠建立一個父類,具備屬性顏色和方法起飛,這樣客運及和戰鬥機這兩個子類就能夠繼承該父類,而後在父類的基礎上擴展本身的屬性和方法.vue
繼承要靠原型來實現,咱們先來了解一下原型的概念.web
查找一個對象的屬性或者方法,首先會在該對象上查找,找不到會沿着原型鏈向上查找,所以實現繼承也就是使得一些方法和屬性在該對象的原型鏈上,這樣該對象也就具備了這些屬性和方法.瀏覽器
原型鏈的繼承即建立構造函數的多個實例,從而這多個實例就擁有了構造函數的屬性和方法.示例代碼:異步
// 片斷A
function Plane(color) {
this.color = color
}
Plane.prototype.fly = function() {
console.log('flying')
}
// Fighter 構造函數
function Fighter() {
this.bullets = []
}
// 繼承Plane構造函數的屬性和方法
Fighter.prototype = new Plane('blue')
// 特有方法
Fighter.prototype.shoot = function() {
console.log('biu biu biu')
}
var fighter1 = new Fighter()
console.log(fighter1.color) // blue
fighter1.fly() // flying
複製代碼
這樣fighter1就具備了父類Plane的color屬性和fly方法,並在此基礎上擴展了本身的shoot方法.函數
constructor指向問題 代碼片斷A的寫法會致使一個constructor指向的問題.工具
// 正常狀況下
function A(color) {
this.color = color
}
var a = new A()
a.__proto__ = A.prototype
a.constructor = A.prototype.constructor = A
// 片斷A的寫法
filter.__proto__ = Filter.prototype
filter.constructor = Filter.prototype.constructor
// 因爲Filter.prototype = new Plane(),咱們手動更改了Filter的prototype屬性
// 因此有
Filter.prototype.constructor = Plane
filter.constructor = Plane
// 爲了解決上述問題,咱們須要對片斷A的代碼作如下調整
Fighter.prototype. = new Plane()
Fighter.prototype.constructo = Fighter
console.log(filter.constructor) // Filter
複製代碼
屬性共享問題post
多個實例共享父類構造函數的屬性,若是共享的屬性是引用類型,會致使其中一個示例最這些屬性作了更改影響到其餘實例中對該屬性的使用.屬性共享會致使數據污染,代碼的可維護性下降.優化
如代碼片斷A這樣,Fighter構造函數建立的實例的繼承得來的color屬性都是blue,實例的顏色最好統一是blue,否則後面一個個修改color,代碼的複用性的下降了.this
// 片斷B
function Plane(color) {
this.color = color
}
Plane.prototype.fly = function() {
console.log('flying')
}
function Fighter(color, content) {
Plane.call(this, color)
this.content = content
}
Fighter.prototype.shoot = function() {
console.log('biu biu biu')
}
var flighter1 = new Fighter('blue', 'zidan');
console.log(flighter1.color); // blue
console.log(flighter1.content); // zidan
flighter1.shoot(); // 'biu biu biu';
flighter1.fly(); // Uncaught TypeError: flighter1.fly is not a function
at <anonymous>:19:15
複製代碼
構造函數繼承的不足就片斷B中既能夠看出,它只能實現繼承構造函數自己的屬性和方法,而不能繼承構造函數原型上的屬性和方法.
組合繼承, 顧名思義是原型鏈繼承和構造函數函數繼承的組合.父類的屬性經過構造函數繼承爲私有屬性,父類的方法經過原型鏈繼承,彌補了原型鏈繼承和構造函數繼承的不足
function Plane(color) {
this.color = color
}
Plane.prototype.fly = function() {
console.log('flying')
}
function Fighter(color) {
Plane.call(this, color)
this.bulltes = []
}
Fighter.prototype = new Plane()
Fighter.prototype.constructor = Fighter
Fighter.prototype.shoot = function() {
console.log('biu biu biu')
}
複製代碼
組合繼承的方法致使了咱們重複調用了構造函數Plane.且Plane構造函數內部的color不會被用到,致使了屬性冗餘.
// 片斷C
function Plane(color) {
this.color = color
this.pilots = []
}
Plane.prototype.fly = function() {
console.log('flying')
}
// Fighter 構造函數
function Fighter(color) {
Plane.call(this, color)
this.bullets = []
}
// 繼承Plane構造函數的屬性和方法
inheritPrototype(Fighter, Plane)
// 特有方法
Fighter.prototype.shoot = function() {
console.log('biu biu biu')
}
var fighter1 = new Fighter()
console.log(fighter1)
// inheritPrototype的第一種實現方式
function inheritPrototype(child, parent) {
var proto = Object.create(parent.prototype)
proto.constructor = child
child.prototype = proto
}
// inheritPrototype的第二種實現方式
function inheritPrototype(child, parent) {
var proto = Object.create(parent.prototype)
child.prototype = proto
child.prototype.constructor = child
}
// inheritPrototype的第三種實現方式
function inheritPrototype(child, parent) {
var proto = function() {}
proto.prototype = parent.prototype
child.prototype = new proto()
child.prototype.constructor = child
}
複製代碼
咱們都知道,目前的js的繼承的實現比較繁瑣, 要調用構造函數,又要本身封裝繼承原型的函數,因此ES6標準將class聲明類和繼承類的方式歸入標準,示例代碼以下:
// 片斷D
class Plane1 {
constructor(color) {
this.color = color
}
fly() {
console.log('flying')
}
}
// 使用extends關鍵字實現繼承
class Fighter1 extends Plane1 {
constructor(color, content) {
super(color)
this.content = content
}
shoot() {
console.log('biu biu biu')
}
}
const fight1 = new Fighter1('blue', 'zidan')
fight1.color // blue
fight1.content // zidan
fight1.fly() // flying
fight1.shoot() // biu biu biu
複製代碼
注意: 目前部分現代瀏覽器新版本已經實現對 ES6 中的class和繼承的,可是注意在舊版本或者 IE 瀏覽器中是不支持的,因此使用的時候要注意,或者配合使用 Babel 等編譯工具。
啦啦啦~~~,寫完了,後續我會堅持一系列的前端知識的分享的,但願大家讀完個人文章後可以有所收穫~~~.聽明白和講明白之間仍是差了不少,若是我有表達不當的地方或者能夠優化的地方還請指出,但願努力的咱們都能成爲優秀的本身~~~