js 原型鏈、__proto__、prototype

本文由用途意義,進行腦測解析,從需求角度走一遍原型鏈的發展。
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__.xthis

通俗點總結,就是給對象掛一個父對象,當對象沒有相應屬性時,就去它父對象那裏找。
prototype


__proto__指向構造函數的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這些東西了。

先提一下,ObjectFunction都是一個函數對象,跟上面的A差很少,既能new Object()也能Object.xxx這樣用。

Object:

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 下面再講。

Function:

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這套東西根本目的是批量爲對象賦予屬性同時減小代碼冗餘,上面解析的ObjectFunction、例子中的A都只是函數對象,不是像java同樣的類,平時說對象的類型只是方便平常交流,instanceof也只是很粗暴的遞歸比較對象__proto__ === 函數對象.prototype這種。把類的概念丟掉,保留對象、屬性這概念,從這出發又回頭去實現「類」、「繼承」這東西,就出來這麼套東西。

相關文章
相關標籤/搜索