一丶前言
最近的學習中總是時不時的遇到原型相關問題,不勝困擾,於是決定學學哪吒鬧海,對“東海三太子”進行抽筋拔骨。希望你在看完本文之後感受是這樣的:
二丶我有故事,君有酒否?
世人皆愛聽故事,在聽各種之乎者也之前不如容小生給大家講個故事。在很久很久以前,js是孤獨的,他沒爹沒媽,沒妻沒子。js轉念一想,總不能叫孤兒吧,於是美其名曰:“null先生”。有一天,null先生撿到了一隻雞和一枚雞蛋,很是高興,給雞蛋取名為Object
,由於他先看到雞後看到蛋,於是他認為雞是屬於他的,這隻雞呢又是由雞蛋孵化的,為了方便理清這層關係,他使用prototype
和__proto__
來進行區分,並規定:
Object.prototype = 雞;
雞.__proto__ = null;複製程式碼
以圖示之:
null先生並不安分,他認為雞給他帶來了很多樂趣,他得回報啊,於是他動手為雞造了一個雞窩,並規定,這個雞窩是給雞的,於是:
雞窩.__proto__ = 雞;複製程式碼
以圖示之:
自從有了這個雞窩,null先生從此和雞過上了沒羞沒臊的生活。。。。。。額,不是,是有了這個雞窩,雞居然生小雞了,但凡這隻雞走進雞窩,沒多久就能從裡面產出小雞來,amazing!null先生想這肯定是這個雞窩的功勞,興奮之餘,他發現雖然都是雞,但顏色,大小等都各有差異,大家都是雞,你裝什麼高貴。null先生雖然這麼想,但為了區分還是根據它們的特性進行命名:String
、Number
、Boolean
、Array
。。。。。。這時null先生再望向那枚起始的雞蛋,一拍大腿,雞生蛋,蛋生雞,這枚雞蛋(Object
)也可以歸屬到雞窩才是!
Object.__proto__ = 雞窩;複製程式碼
null先生以為日子總該平靜了吧,但雞就是雞,一天不搞事渾身難受,有一種渾身彩色的小雞我們簡稱為彩雞,它幹了什麼呢?它居然可以自己造窩,不僅如此,它造出來的雞窩和null先生造的雞窩功能是一樣的,也能產小雞,null先生不禁歎服:好你個彩雞,居然有如此之本領,這般放蕩,要剋制自己的本性才好。於是給這種彩雞取名為“放克性”,彩雞不服,兄弟姐妹們都是英文名憑啥我是中文名,便自我改名Function
。有了這層關係,我們大膽得出結論:
String.__proto__ = 雞窩;
Number.__proto__ = 雞窩;
...
Function.__proto__ = 雞窩;
Function.prototype = 雞窩;複製程式碼
以圖示之:
啊~null先生大嘆一聲,這日子什麼時候是個頭啊!其實,這才剛剛開始。。。。。。
好了,故事講完了,根據以上資訊我們得出以下結論:
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 = 原型物件
,現在再想想那群雞和雞窩是不是恍然大悟,雞窩原來就是原型物件!
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 世界萬物誕生記