什么是繼承
根據維基百科解釋,可以簡單概括為:
繼承是類與類之間的關系,其作用是使得子類具有父類別的各種屬性和方法。
JS 里的原型繼承模型
JS:不好意思,我沒有類。(即使是ES6中的類也是語法糖)
JavaScript 是基于原型實現面向對象的,那么在JS中,面向對象概念中的繼承自然也是基于原型。
當談到繼承時,JavaScript 只有一種結構:對象。每個實例對象(object )都有一個私有屬性(稱之為[[prototype]])指向它的原型對象(prototype)。該原型對象也有一個自己的原型對象 ,層層向上直到一個對象的原型對象為
null
。根據定義,null
沒有原型,并作為這個原型鏈中的最后一個環節。
幾乎所有 JavaScript 中的對象都是位于原型鏈頂端的 Object 的實例。
有關原型之前寫過博客JavaScript原型和原型鏈,對理解下面內容有幫助。
雖然沒有傳統語言意義上的類,但是 JS語言 使用構造函數生成對象,實現面向對象程序設計。
說了這么多,JS 中的繼承到底是什么?
可以簡單理解為:兩次的原型搜索就是繼承。
數組 a 從 Array 中原型搜索到 toString 屬性,只是實例屬性;a 從 Array 中原型搜索到 (Array 從 Object 中原型搜索到的)valueOf 屬性,可以稱為繼承。
接下來我們用代碼實現一下繼承
1. 使用 prototype 實現繼承
prototype 的作用:為構造函數內添加實例對象之間的共有屬性
明確 JS 內的繼承
以下面代碼為例
// 構造一個 人類
function Human(name){
this.name = name
}
// 給所有 人類 添加一個 跑 的共有屬性
Human.prototype.run = function(){
console.log("我叫"+this.name+",我在跑")
return undefined
}
// 構造一個 男人類
function Man(name){
Human.call(this, name)
this.gender = '男'
}
// 所有 男人 都有好戰屬性
Man.prototype.fight = function(){
console.log('糊你熊臉')
}
可以看到名為 ada 的人只有 name、gender 和fight 這些 Man 構造函數里面含有的屬性,而沒有我們希望的 Human 應該有的 run 的屬性。
目標:假如我們有方法讓 ada 有了 Man 里面沒有的 run 屬性,即我們自己實現了 Man 繼承 Human 的過程。
根據我原型知識的博客里面的內容我們知道,我們可以直接:
Man.prototype.__proto__ = Human.prototype
可以看到 Man 指向了 Human 而不是直接指向 Object,ada2 繼承了來自 Human 的 run 屬性
但是在實際編程過程中直接操作 __ proto __ 這個非標準但許多瀏覽器(IE不支持)實現的屬性是不規范的。
那怎么辦?
new 可不可以?
Man.prototype = new Human()
直接用上述代碼不行,因為在 new 的過程中,雖然new 內部實現了 Man.prototype.__proto__ = Human.prototype
這一個過程,但是由于 new 同時會在內部執行構造函數,而在執行過程中我們未傳 name,因此上圖中 Human 的 name 屬性顯示 undefined
那么我們只要避免這個過程中 Human 執行就可以了
var a = function(){}
a.prototype = Human.prototype
Man.prototype = new a()
通過上面三行代碼,即實現了沒有內部執行空函數的 new
2. ES6 實現繼承
上面代碼的 ES6 版本
// ES6 寫法
class Human{
constructor(name){
this.name = name
}
run(){
console.log("我叫"+this.name+",我在跑")
return undefined
}
}
class Man extends Human{ // extends 實現上述繼承過程
constructor(name){
super(name) // 調用構造函數:'超類'
this.gender = '男'
}
fight(){
console.log('糊你熊臉')
}
}
文章開頭已經提到, ES6 的 class 是語法糖,其實質就是函數,而上述用 class 實現繼承的過程,還是基于原型鏈(和 ES5 的是不是完全一致)
總結:
JS 繼承的原型寫法相對 ES6 的寫法看上去似乎更復雜,但是事實上更好理解;class 的寫法更符合面向對象編程的思維,由于是語法糖因而自然寫法簡便,但其有一定局限性。
原型繼承模型本身實際上比經典模型更強大
感謝閱讀
本文僅供個人學習使用
部分參考:繼承與原型鏈