本文由用途意義,進行腦測解析,從需求角度走一遍原型鏈的發展。
java
js中沒有類(沒有類,沒有類,重要的事情說3遍)只有對象,怎麼才能作到繼承的效果?c++
var a={x:1} var b={}; b.__proto__=a;
接下來進行約定,當訪問b.x
但不存在時,就自動去訪問b.__proto__.x
。函數
邏輯上就這麼一回事。不過須要注意,這裏說的只是訪問。b.x=2
這種是沒法對a,也就是b.__proto__
形成影響的;同時這個爲b賦予了x屬性,b.x
將覆蓋掉b.__proto__.x
。this
通俗點總結,就是給對象掛一個父對象,當對象沒有相應屬性時,就去它父對象那裏找。
prototype
var A=function(){ } var b = new A();
這個時候又該怎樣用__proto__實現繼承效果?code
首先函數也是一個對象,除了A();
這樣以函數調用,還能A.x=1;
這樣把A當普通對象使用(下文中函數、函數對象,都是一回事)。知道這個後實現繼承很簡單,增長一個屬性便可:對象
A.prototype={constructor: A};//提醒一下怕忘記了,這裏至關於A增長了屬性prototype A.prototype.x=1; b.__proto__ = A.prototype;
js會爲每一個這樣new出來的對象作這個處理,本身不用寫。繼承
顯然,這裏的A.prototype
就相似與一開始例子中的a
,往A.prototype增長屬性,那麼全部new A()
出來的對象都能訪問到這個新的屬性。遞歸
爲何js要默認增長constructor: A
這個屬性到prototype中?這裏與new操做符有關,是爲了解決另外一個問題。另外常說的prototype的構造函數,就是指這個。原型鏈
總結:
反正就是經過new 函數()
這樣出來的對象,其__proto__默認指向構造函數(這裏說的是函數對象自己,它跟在new後面也被稱做構造函數)的prototype屬性。
實際上我以爲通常不以這個方法進行有大量屬性的繼承,一是查找有無屬性的效率問題,二是new時構造方法把this改成新建對象的指向就足以完成屬性的添加和賦值,無需操做prototype進行繼承。
__proto__、prototype是什麼一回事相信已經瞭解,剩下的就是常常把人繞暈的Object.prototype、Function.prototype這些東西了。
先提一下,Object
、Function
都是一個函數對象,跟上面的A
差很少,既能new Object()
也能Object.xxx
這樣用。
1.因此var b=new Object();
後,b.__proto__===Object.prototype
這個應該沒有什麼疑問。
2.新的標準中可用b=Object.creat(a)
,可看成是b=new Object(); b.__proto__=a
,仍是這套操做,問題不大。
3.若是是var b={}
這種直接經過字面量建立對象,js會自動進行b.__proto__=Object.prototype
,知道後問題也不大。
4.就是默認狀況下,你不手動搞__proto__、prototype的指向,最終__proto__都會去指向Object.prototype。
5.Object.prototype
本質上跟前面示例中的prototype沒什麼不一樣,只是這個prototype會被js自動增長一些屬性
6.Object.prototype.__proto__===null
跟在c++/java中遍歷鏈表同樣,當__proto__爲null時說明到頭了。看成js自動設置上去的就行,沒什麼其餘特殊
7.Object.__proto__===Function.prototype
下面再講。
1.全部的函數對象都是Function的實例。
不是說沒有類嗎,這個實例又是什麼意思?
emmm,習慣說法而已,具體什麼操做沒研究也不懂,或許看成js自動這樣作:
var f=function(){} f.__proto__=Function.prototype; //或者這樣理解 var f=new Function(); 而後把你的代碼放進去f
2.Function.__proto__===Function.prototype;
前面提過Object、Function都是一個函數對象,把它們代入第1點例子的f
就行。上面第6點同理。
按照理解,可能會這樣的疑問:Function.__proto__指向構造函數(再次提醒,是一個對象)的prototype,因此Function這個對象的構造函數是它本身?本身建立本身麼?
額。。。我以爲這種操做可能就是爲了統一,只要記住「全部函數對象的__proto__都是Function.prototype」就行。
3.Function.prototype.__proto__===Object.prototype;
沒什麼特別的,把Function.prototype
代入上面Object第1點的b
就行,不要特殊看待,硬要說與b
不一樣的話,只是由於「函數對象的prototype默認會被增長一個constructor屬性」而已,沒什麼大問題
1.咱們在js中說的「類型」,能夠說只是習慣用語,實際上仍舊是沒有所謂的類概念的,只有用對象來「模擬類」。
2.prototype就是指向一個普通對象prototype=new Object()
,只不過這個對象被添加其餘一些屬性後,再被自動放到到函數對象的屬性中。
3.__proto__就是 原型/原型對象,不斷的找原型的原型最終到--->Object.prototype--->Object.prototype.__proto__ (null)。原型對象多是一個普通的對象;也多是js自動放入到函數對象的prototype
4.我以爲js這套東西根本目的是批量爲對象賦予屬性同時減小代碼冗餘,上面解析的Object
、Function
、例子中的A
都只是函數對象,不是像java同樣的類,平時說對象的類型只是方便平常交流,instanceof也只是很粗暴的遞歸比較對象__proto__ === 函數對象.prototype
這種。把類的概念丟掉,保留對象、屬性這概念,從這出發又回頭去實現「類」、「繼承」這東西,就出來這麼套東西。