圖1 關係圖解javascript
__proto__(雙橫線):javascript中對象內置的隱藏屬性,相似指針,指向其引用對象的原型對象。java
prototype:函數對象的一個屬性,也相似於一個指針,指向其原型對象。函數
Point{}:Point的原型對象。測試
Point:Point的構造函數。this
如圖1,定義一個函數 Point(),其中Poin對象增長p1屬性,Point原型對象增長一個sum方法。p1,p2爲Point()的實例化對象,name1,name2分別爲p1,p2的屬性。代碼以下:prototype
function Point(){指針
var p1 = "測試點";對象
}blog
Point.prototype.sum = function (){繼承
var sum = function(){
return 1+2;
}
}
var P1 = new Point();
var P2 = new Poin();
P1.name1 = "點1";
P2.name2 = "點2";
P1擁有的屬性和方法:sum方法,Name1屬性。
P2擁有的屬性和方法:sum方法,Name2屬性。
javascript搜索一個對象的屬性和方法,先默認搜索自身的屬性和方法,若是自身沒搜索到,再經過__proto__屬性找到其引用對象的原型對象,如此經過__proto__一層層往下找,最終__proto__的指針指向null;
諸如:P1-->Point{}-->Object{}-->null 經過__proto__造成的一條鏈路,這條鏈路即是原型鏈。
經過上述代碼模擬了一個Point類 ,其中p1爲Point的私有屬性,sum爲Point的公共方法。經過new Point()創建的爲Point的實例化對象,擁有Point的全部公共屬性和方法。
若想獲取 Point的私有屬性,能夠進行以下改造:
function Point(){
var p1 = "測試點";
this.getP1 = function (){
return p1;
}
}
這樣,就能對Point實現封裝,提供讀取p1屬性的方法。
有了Point類,也能進行封裝了,那如何實現繼承?
由關係圖可知,經過 Animal.prototype = new Point(); 就能夠實現繼承,Animal繼承了Point,擁有Point的全部公共屬性和方法。A1爲Animal的實例化對象,則A1 不只擁有Animal的全部公共屬性和方法,並且擁有Point的全部公共屬性和方法。代碼以下:
function Animal(){
var add1 = function (){ return "add1";};
this.add2 = function (){ return "add2";};
}
Animal.prototype.run = "run"; //此行不是代碼內容,只是爲了測試更改原型對象後此屬性是否還存在。
Animal.prototype = new Point();
var A1 = new Animal();
此時A1擁有的屬性和方法爲:add2方法,sum方法。add1做爲Animal的私有方法沒法獲取,run則屬性Animal之前的原型對象的屬性,也沒法獲取,sum做爲Animal繼承的方法,可以獲取。而A1可以擁有add2方法則是由於在Javascript中,this指向函數執行時的當前對象該關鍵字在Javascript中和執行環境,而非聲明環境有關。 this關鍵字雖然是在定義Animal的時候生成的,可是在new Animal()的時候才執行,所以add2得以存在。
PS:本身畫的圖和寫的內容,非轉載,剛畢業的菜鳥,若是我理解的有不對的地方歡迎你們指正。
另:原型鏈當然強大,可是由於javascript是動態語言,經過原型鏈甚至能修改繼承的父類的屬性和方法,還能給父類增長讀寫方法。關於如何防止別人隨意篡改父類的屬性,還請大牛們指點一二。