原型和原型鏈的抽筋拔骨

一丶前言

最近的學習中老是時不時的遇到原型相關問題,不勝困擾,因而決定學學哪吒鬧海,對「東海三太子」進行抽筋拔骨。但願你在看完本文以後感覺是這樣的:javascript


二丶我有故事,君有酒否?

世人皆愛聽故事,在聽各類之乎者也以前不如容小生給你們講個故事。在好久好久之前,js是孤獨的,他沒爹沒媽,沒妻沒子。js轉念一想,總不能叫孤兒吧,因而美其名曰:「null先生」。有一天,null先生撿到了一隻雞和一枚雞蛋,非常高興,給雞蛋取名爲Object因爲他先看到雞後看到蛋,因而他認爲雞是屬於他的,這隻雞呢又是由雞蛋孵化的,爲了方便理清這層關係,他使用prototype__proto__來進行區分,並規定:html

Object.prototype = 雞;
雞.__proto__ = null;複製代碼

以圖示之:java


null先生並不安分,他認爲雞給他帶來了不少樂趣,他得回報啊,因而他動手爲雞造了一個雞窩,並規定,這個雞窩是給雞的,因而:bash

雞窩.__proto__ = 雞;複製代碼

以圖示之:函數


自從有了這個雞窩,null先生今後和雞過上了沒羞沒臊的生活。。。。。。額,不是,是有了這個雞窩,雞竟然生小雞了,但凡這隻雞走進雞窩,沒多久就能從裏面產出小雞來,amazing!null先生想這確定是這個雞窩的功勞,興奮之餘,他發現雖然都是雞,但顏色,大小等都各有差別,你們都是雞,你裝什麼高貴。null先生雖然這麼想,但爲了區分仍是根據它們的特性進行命名:StringNumberBooleanArray。。。。。。這時null先生再望向那枚起始的雞蛋,一拍大腿,雞生蛋,蛋生雞,這枚雞蛋(Object)也能夠歸屬到雞窩纔是!學習

Object.__proto__ = 雞窩;複製代碼

null先生覺得日子總該平靜了吧,但雞就是雞,一天不搞事渾身難受,有一種渾身彩色的小雞咱們簡稱爲彩雞,它幹了什麼呢?它竟然能夠本身造窩,不只如此,它造出來的雞窩和null先生造的雞窩功能是同樣的,也能產小雞,null先生不由歎服:好你個彩雞,竟然有如此之本領,這般放蕩,要剋制本身的本性纔好。因而給這種彩雞取名爲「放克性」,彩雞不服,兄弟姐妹們都是英文名憑啥我是中文名,便自我更名Function。有了這層關係,咱們大膽得出結論:spa

String.__proto__ = 雞窩;
Number.__proto__ = 雞窩;
...
Function.__proto__ = 雞窩;
Function.prototype = 雞窩;複製代碼

以圖示之:.net


啊~null先生大嘆一聲,這日子何時是個頭啊!其實,這纔剛剛開始。。。。。。prototype

好了,故事講完了,根據以上信息咱們得出如下結論:指針

Object.__proto__ === Function.prototype;
Function.prototype.__proto__ === Object.prototype;
Object.prototype.__proto__ === null;複製代碼

三丶給對象劃分三六九等

咱們常說「萬物皆對象」是由於javascript任何值或變量都是對象,可是對象也能夠劃分爲三六九等。

公爵——Object

Javascript中全部的對象都是Object的實例,並繼承Object.prototype的屬性和方法,全部的對象都是間接或直接的經過Object衍生的。這個大哥Object當之無愧。

侯爵——Function

當咱們定義一個對象時,能夠用var obj = new Object(),咱們都知道new是用來實例化一個對象的方法,可是咱們都知道javascript中不存在真正的類的概念,因此只能用函數來模擬,那麼既然能夠有上面的作法也就印證了Object也是特殊的函數。  咱們回到剛纔的故事,Object是蛋,Function是雞,那你以爲是雞生蛋仍是蛋生雞呢?成年人沒空思考,小孩又想不出答案。。。。。。

伯爵——String,Number,Boolean,Array...

子爵——其餘

四丶原型和原型鏈

講了這麼多,那麼到底何爲原型,何爲原型鏈呢???

4.1 原型

每一個函數都有prototype(原型)屬性,這個屬性是一個指針,指向一個對象,這個對象的用途是包含特定類型的全部實例共享的屬性和方法,咱們稱這種對象爲原型對象,即這個原型對象是用來給實例共享屬性和方法的。也就是說Function.prototype = 原型對象,如今再想一想那羣雞和雞窩是否是恍然大悟,雞窩原來就是原型對象!

既然函數這麼特殊,那麼咱們在此將對象分爲 函數對象普通對象,函數對象是經過使用function定義的對象,而普通對象是經過使用 new操做符生成的對象。函數對象有一個 prototype屬性,普通對象就沒有這個 prototype屬性,存在 __proto__。咱們來看幾個例子:

var obj = new Object();
console.log(obj.__proto__);//Object原型對象
console.log(obj.prototype);//undefined
console.log(Object.prototype);//Object原型對象
console.log(obj.__proto__ === Object.prototype)//true


var Fn = function(){};
var fn = new Fn();
console.log(Fn.prototype);//Object {constructor: function}
console.log(fn.__proto__);//Object {constructor: function}
console.log(fn.__proto__ === Fn.prototype);//true複製代碼

實際上每一個實例內部都有一個指向原型對象的指針。所以:若var a = new A();則a.__proto__=A.prototype

4.2 原型鏈

談到原型鏈就不得不談到__proto__,上面咱們有談到,每一個對象都會在其內部初始化一個屬性,就是__proto__當咱們訪問一個對象的屬性時,若是這個對象內部不存在這個屬性,那麼它就會去__proto__裏找這個屬性,這個__proto__又會有本身的__proto__,因而就這樣 一直找下去,也就是咱們平時所說的原型鏈的概念。舉一個構造函數中常常遇到的實例:

var Fn = function(){};
Fn.prototype.sayLove = function(){
    console.log("I love XX");
}
var fn = new Fn();
fn.sayLove();//I love XX;複製代碼

當咱們調用fn.sayLove()時會輸出"I love XX",那麼fn是如何找到這個方法的呢?首先fn做爲實例對象,自己並不存在sayLove()方法,從而它就會去找fn.__proto__,由於fn是Fn的實例,所以fn.__proto__ = Fn.prototype,而咱們上邊定義了Fn.prototype.sayLove = function(){},所以fn.sayLove()天然也就輸出了"I love XX"。

初來貴寶地,有錢的捧個贊場,沒錢的點個關注再走。

五丶參考資料

深刻理解JavaScript原型鏈
Object.prototype原型和原型鏈
JS原型和原型鏈是什麼?
JavaScript 世界萬物誕生記
相關文章
相關標籤/搜索