來源: 我的博客
學過「面向對象」的同窗們是否還記得,老師成天掛在嘴邊的面向對象三大特徵:封裝,繼承,多態。今天咱們就來白話一下javascript中的原型繼承,沒學過的同窗們也不用擔憂,跟着往下走,我相信你會明白的。javascript
繼承,固然是面向對象其中的一種思想和概念了,所謂繼承,顧名思義就是繼承了。。。html
好比說小明是老明惟一的兒子,老明有一個億的資產,這一個億的資產雖然不在小明手裏,可是小明是老明兒子,小明在必定程度上「繼承」了他老爸給他提供的這麼多的資產,小明不只能夠享用本身賺來的錢,也能夠隨時消費他父輩的資產。java
在程序中,其實也是相似的,若是一個對象A繼承了對象B,那麼對象A不只可使用本身的屬性和方法,同時也可使用父級B中的屬性和方法。git
爲了可以說明白Javascript 中的原型繼承,就不得不說javascript中的對象。es6
在javascript中你可使用如下方式建立一個javascript 對象(object).github
第一種對象字面量方式很簡單粗暴:chrome
var a = {}; // 我建立了一個空對象a
第二種「構造函數」方式來「建立對象」。瀏覽器
「構造函數」只是建立一個對象的第一步!有了構造函數以後,第二部就是用它建立一個對象!app
因此, 第一步,來一個構造函數,你能夠把它當成一個普通函數,好比:函數
function People(name) { this.name = name; }
這個函數也能夠接受參數,若是你們對this關鍵字不瞭解,請先看《詳解javascript this關鍵字》這個教程,這裏我就不囉嗦了。
咱們有了構造函數以後,第二步開始使用它構造一個函數。
在javascript中,咱們使用 「new」 操做符 + 構造函數 來建立一個對象。
var a = new People('xiaoming'); var b = new People;
順便提一下,若是你不想給構造函數傳入參數,那麼帶不帶括號都是同樣的,也就是說:
var a = new People; var b = new People();
這兩種建立對象方式都正確。
小提示:其實第一種對象字面量方式只是構建對象的語法糖(syntax sugar),底層仍是使用構造函數方式構造的:
new Object()
你們不相信的話,能夠打開你的chrome的控制檯,直接輸入:
Object
是否是看到了下面這一行?
function Object() { [native code] }
這個Object也是個構造函數,只不過這裏原生代碼。
如今你們知道了javascript中對象建立的兩種方式。
var a = {}; var xiaoming = new People();
接下來這句話請你們重複三遍:
全部的javascript對象都從一個叫「原型」的地方繼承了全部的屬性和方法!
這個「原型」是個啥?就是個對象!你能夠把它想象成:{}。
咱們前面說了建立對象的兩種方法:
1, 對象字面量
var a = {}; // 其實等於 var a = new Object;
2, 構造函數
function People(){ } var a = new People();
咱們說過了:
全部的javascript對象都從一個叫「原型」的地方繼承了全部的屬性和方法!
上面這兩個例子中對象是:
a
那麼原型(prototype)在哪呢?你們試着和我同樣作一下:
console.log(Object.prototype); console.log(People.prototype);
是否是都輸出了一個對象?
咱們以前也說了,原型(prototype)就是一個對象而已,如今你們也知道它在哪了吧?原型就是構造函數的一個屬性,這裏可能聽着有點彆扭,函數的屬性?對,javascript中的構造函數也是對象!
重要的事情說三遍:javascript的原型(prototype)是什麼?就是「構造函數」下的一個對象叫作「原型」(prototype)
再添一句,這個原型對象中又有個名爲「constructor」的屬性,指向了該函數自己。
function People(){} People.prototype.constructor === People // true
再提醒一下,原型只存在在「構造函數」中,有些同窗會誤解的去找一個「對象」或「對象字面量」的原型(prototype),由於咱們說了原型(prototype)只存在在「構造函數」中,因此去對象或對象字面量裏找原型的找不到的,只能返回undefined。好比:
var a = {}; console.log(a.prototype) // 返回undefined // 或者 function People() {} var p = new People; console.log(p.prototype) // 依然返回undefined // 可是 console.log(People.prototype) // 就返回一個{} 固然這裏面有好多原生的方法
可是,還有一個特別屬性
__proto__
可讓你「向父級」查看,當前對象繼承的「原型」是誰?就是孩子找爸爸。
打開你的chrome瀏覽器的控制檯,接着上面的代碼繼續試驗:
a.__proto__ // Object {} p.__proto__ // Object {} a.__proto__ === Object.prototype // true p.__proto__ === People.prototype // true // 咱們發現兩個對象的原型都是對象。 // 那麼咱們再來看看構造函數「繼承」的原型是誰? Object.__proto__ // function () {} People.__proto__ // function () {}
看到這裏,但願你能明白,不論是javascript自帶的,仍是咱們自定義的構造函數依然繼承自匿名函數的原型!(但願你沒暈)
有了上面的鋪墊,咱們終於可以開始說一下原型繼承了。若是你上面的知識點都理解了,理解原型繼承不在話下。
來個例子:
function People(name) { this.name = name; } People.prototype.sayHi = function () { console.log('hi, my name is ', this.name); }; var a = new People('xiaoming'); a.sayHi(); // hi, my name is xiaoming var b = new People('laoming'); b.sayHi(); // hi, my name is laoming
這種方式很簡單也很直接,你在構造函數的原型上定義sayHi方法,那麼用該構造函數實例化出來的對象均可以經過原型繼承鏈訪問到定義在構造函數原型上的方法。
理解了上述內容,你能夠直接利用javascript的原型繼承,也能夠用它爲基礎構造本身「類」感受小庫。