注意這個系列文章,要常常站在JS之父的視角去思考。數組
牢記咱們的需求,我要在JS沒有class的狀況下,那麼利用JS現有的東西,搞出相似class的東西。瀏覽器
回一下JS有什麼? 有7種數據類型:函數
對象分紅3類: 普通對象 、數組對象 、函數對象。spa
思考問題1: 咱們都知道array function都屬於object,那麼既然他們都是對象,必定有某些相同之處吧,對象和對象之間有什麼關聯呢?prototype
若是說你沒有思考過這個問題,那麼能夠換一個更具體的問題。設計
思考問題2: 打印這段代碼,到瀏覽器控制檯,你會發現咱們空對象,"自帶"了一個toString()?code
var obj = { name: 'ziwei', sex : '男', eat : function(){} } obj.toString()
問題1: array funciton obj 都是對象,那麼爲何說他們都是對象,經過什麼關聯起來的?對象
問題2: 爲何一個空對象,"自帶"toString()方法?繼承
若是你不清楚以上問題的答案,恭喜你,這篇文章的主題【原型鏈】就能夠清楚的解答你的疑惑。圖片
仍是上面這段代碼
var obj = { name: 'ziwei', sex : '男', eat : function(){} } obj.toString()
若是咱們想本身實現,讓obj,具備toString()怎麼辦? 直覺確定是添加在obj上咯。
這樣由於toString(),是函數對象,因此須要在內存中開闢一塊空間,存放toString()
如今,咱們要聲明100個obj對象,他們都須要具有toString()怎麼辦?
若是循環100次給每一個obj都添加toString(),須要在內存空間開闢100個空間,存在100個相同的toString(),勢必形成內存空間的浪費,在JS被創造時,內存仍是十分寶貴的資源。
因此JS之父想出一個辦法。把對象須要共享的屬性和方法,放到一個內存空間裏,而後每個對象都有一個屬性都指向這一個空間。
因此原型鏈被髮明,最樸素的想法就是節省內存空間。
1.全部對象都有的這個屬性長得很奇怪,叫作 proto
var obj = {} console.log(obj.__proto__ ) 訪問,你就能夠查看全部object都共享的屬性。
2.這個__proto__所指向的那塊內存空間裏的屬性,並非在var obj = {}時,才被添加進去的,而是一直都存在的。
經過 window.Object.prototype 你一樣能夠訪問到這個共享的內存空間
3.__proto__裏面還能夠有__proto__,畢竟被稱爲原型鏈嘛。
之因此須要"鏈",你能夠看這樣一個例子
var arr = [] 數組做爲一個數組是有push()方法的, 但是咱們查看 window.Object.prototype裏並無共享push方法
咱們爲了實現數組有push方法,可是不能讓全部的對象都有push方法,爲了實現這個需求,JS是這樣設計的。
JS另外開闢了一個內存空間,用來專門存儲數組的共有方法和屬性。你能夠用過window.Array.prototype來訪問它
這樣JS數組,arr經過__proto__繼承了Array.prototype的方法,有經過Array.prototype.__proto__繼承了Object.prototype上的訪問。
相似的咱們訪問obj.name時,JS會在obj內部尋找name屬性,若是沒有,就會到__proto__中去尋找name,一直到Object.prototype若是仍是沒有name,就會返回undefined
因此這種依靠原型來繼承的方式,很想一個鏈條,一層一層的向上尋找,因此叫作原型鏈,原型鏈的頂端就是Object.prototype
問題1: array funciton obj 都是對象,那麼爲何說他們都是對象,經過什麼關聯起來的?
他們就是經過__proto__關聯的。
Array.prototype.__proto__ 繼承了 Object.prototype
Function.prototype.__proto__ 繼承了 Object.prototype
他們同根同源,都繼承自Object.prototype,數組只是比普通的對象多了一些方法,因此他們都是對象唄
![圖片上傳中...]
問題2: 爲何一個空對象,"自帶"toString()方法?
由於全部對象都自帶__proto__屬性,這個屬性指向Object.prototype這個內存空間。
由於Object.prototype存儲着有toString(),因此全部對象都有。