關於js中Prototype屬性的解釋和方法,看了某位大佬總結的一片博客,寫的很是好啊,收益了,我這裏轉載備份一下,也加點一些小理解。後面有Prototype屬性的新理解的話,會繼續補充。不過關於原文中的類方法好像有點爭議,有大佬科普下嗎?javascript
原文:http://www.cnblogs.com/wdlhao/p/5743770.htmlhtml
一、prototype的定義java
javascript中的每一個對象都有prototype屬性,Javascript中對象的prototype屬性的解釋是:返回對象類型原型的引用。設計模式
每個構造函數都有一個屬性叫作原型。這個屬性很是有用:爲一個特定類聲明通用的變量或者函數。函數
你不須要顯式地聲明一個prototype屬性,由於在每個構造函數中都有它的存在。你能夠看看下面的例子:測試
function Test(){} alert(Test.prototype); // 輸出 "Object"
1.一、 原型法設計模式this
原型法的主要思想是,如今有1個類A,我想要建立一個類B,這個類是以A爲原型的,而且能進行擴展。咱們稱B的原型爲A。spa
1.二、javascript的方法能夠分爲三類:prototype
a 類方法設計
b 對象方法
c 原型方法
function People(name) { this.name=name; //對象方法 this.Introduce=function(){ alert("My name is "+this.name); } } //類方法 People.Run=function(){ alert("I can run"); } //原型方法 People.prototype.IntroduceChinese=function(){ alert("個人名字是"+this.name); } //測試 var p1=new People("Windking"); p1.Introduce(); People.Run(); p1.IntroduceChinese();
1.三、給prototype添加屬性
就如你在上面所看到的,prototype是一個對象,所以,你可以給它添加屬性。你添加給prototype的屬性將會成爲使用這個構造函數建立的對象的通用屬性。
例如,我下面有一個數據類型Fish,我想讓全部的魚都有這些屬性:livesIn="water"和price=20;爲了實現這個,我能夠給構造函數Fish的prototype添加那些屬性。
function Fish(name, color){ this.name=name; this.color=color; } Fish.prototype.livesIn="water"; Fish.prototype.price=20;
var fish1=new Fish("mackarel", "gray"); var fish2=new Fish("goldfish", "orange"); var fish3=new Fish("salmon", "white"); for (int i=1; i<=3; i++){ alert(fish.name+","+fish.color+","+fish.livesIn+","+fish.price); }
輸出應該是:
"mackarel, gray, water, 20" "goldfish, orange, water, 20" "salmon, white water, 20"
你看到全部的魚都有屬性livesIn和price,咱們甚至都沒有爲每一條不一樣的魚特別聲明這些屬性。這時由於當一個對象被建立時,這個構造函數 將會把它的屬性prototype賦給新對象的內部屬性__proto__。這個__proto__被這個對象用來查找它的屬性。
你也能夠經過prototype來給全部對象添加共用的函數。這有一個好處:你不須要每次在構造一個對象的時候建立並初始化這個函數。爲了解釋這一點,讓咱們從新來看Example DT9並使用prototype來重寫它。
1.四、用prototype給對象添加函數
function Employee(name, salary){ this.name=name; this.salary=salary; } Employee.prototype.getSalary=function getSalaryFunction(){ return this.salary; } Employee.prototype.addSalary=function addSalaryFunction(addition){ this.salary=this.salary+addition; } var boss1=new Employee("Joan", 200000); var boss2=new Employee("Kim", 100000); var boss3=new Employee("Sam", 150000);
輸出的結果爲:
alert(boss1.getSalary()); // 輸出 200000 alert(boss2.getSalary()); // 輸出 100000 alert(boss3.getSalary()); // 輸出 150000
子類如何重寫父類的屬性或方法:
function AClass(){ this.Property = 1; this.Method = function(){ alert(1); } } function AClass2(){ this.Property2 = 2; this.Method2 = function(){ alert(2); } } AClass2.prototype = new AClass(); AClass2.prototype.Property = 3; AClass2.prototype.Method = function(){ alert(4); } var obj = new AClass2(); alert(obj.Property); obj.Method();
輸出結果爲:
//3 //4
能夠在對象上增長屬性或方法
function Aclass(){ this.Property = 1; this.Method = function(){ alert(1); } } var obj = new Aclass(); obj.Property2 = 2; obj.Method2 = function(){ alert(2); } alert(obj.Property2); obj.Method2();
輸出結果爲:
//2 //2
function Aclass(){ this.Property = 1; this.Method = function(){ alert(1); } } Aclass.prototype.Property = 2; Aclass.prototype.Method = function{ alert(2); } var obj = new Aclass(); alert(obj.Property); obj.Method();
輸出結果爲:
//1 //1
1.五、A.prototype = new B();
理解prototype不該把它和繼承混淆。A的prototype爲B的一個實例,能夠理解A將B中的方法和屬性所有克隆了一遍。A能使用B的方法和屬性。這裏強調的是克隆而不是繼承。能夠出現這種狀況:A的prototype是B的實例,同時B的prototype也是A的實例。
先看一個實驗的例子:
function baseClass(){ this.showMsg = function(){ alert("baseClass::showMsg"); } } function extendClass(){} extendClass.prototype = new baseClass(); var instance = new extendClass(); instance.showMsg(); // 顯示baseClass::showMsg
咱們首先定義了baseClass類,而後咱們要定義extentClass,可是咱們打算以baseClass的一個實例爲原型,來克隆的extendClass也同時包含showMsg這個對象方法。
extendClass.prototype = new baseClass()就能夠閱讀爲:extendClass是以baseClass的一個實例爲原型克隆建立的。
那麼就會有一個問題,若是extendClass中自己包含有一個與baseClass的方法同名的方法會怎麼樣?
下面是擴展實驗2:
function baseClass(){ this.showMsg = function(){ alert("baseClass::showMsg"); } } function extendClass(){ this.showMsg =function (){ alert("extendClass::showMsg"); } } extendClass.prototype = new baseClass(); var instance = new extendClass(); instance.showMsg();//顯示extendClass::showMsg
實驗證實:函數運行時會先去本體的函數中去找,若是找到則運行,找不到則去prototype中尋找函數。或者能夠理解爲prototype不會克隆同名函數。
那麼又會有一個新的問題:若是我想使用extendClass的一個實例instance調用baseClass的對象方法showMsg怎麼辦?
答案是可使用call:
extendClass.prototype = new baseClass(); var instance = new extendClass(); var baseinstance = new baseClass(); baseinstance.showMsg.call(instance);//顯示baseClass::showMsg
這裏的baseinstance.showMsg.call(instance);閱讀爲「將instance當作baseinstance來調用,調用它的對象方法showMsg」
好了,這裏可能有人會問,爲何不用baseClass.showMsg.call(instance);
這就是對象方法和類方法的區別,咱們想調用的是baseClass的對象方法
1.六、對象方法與經過new建立對象的重要區別
這個區別就是function定義的方法(對象方法)有一個prototype屬性,使用new生成的對象就沒有這個prototype屬性。也就是prototype屬性是對象方法或者構造方法的專有屬性。 prototype屬性又指向了一個prototype對象,注意prototype屬性與prototype對象是兩個不一樣的東西,要注意區別。在prototype對象中又有一個constructor屬性,這個constructor屬性一樣指向一個constructor對象,而這個constructor對象偏偏就是這個function函數自己。以下所示:
(這個圖沒看懂啊=-=,又涉及到了constructor)
function Person(name) { this.name=name; this.showMe=function() { alert(this.name); } }; var one=new Person('js'); alert(one.prototype)//undefined alert(typeof Person.prototype);//object alert(Person.prototype.constructor);//function Person(name) {...};
最後,下面這個代碼若是理解清晰,那麼這篇文章說的就已經理解了:
1 <script type="text/javascript"> 2 3 function baseClass() 4 { 5 this.showMsg = function() 6 { 7 alert("baseClass::showMsg"); 8 } 9 10 this.baseShowMsg = function() 11 { 12 alert("baseClass::baseShowMsg"); 13 } 14 } 15 baseClass.showMsg = function() 16 { 17 alert("baseClass::showMsg static"); 18 } 19 20 function extendClass() 21 { 22 this.showMsg =function () 23 { 24 alert("extendClass::showMsg"); 25 } 26 } 27 extendClass.showMsg = function() 28 { 29 alert("extendClass::showMsg static") 30 } 31 32 extendClass.prototype = new baseClass(); 33 var instance = new extendClass(); 34 35 instance.showMsg(); //顯示extendClass::showMsg 36 instance.baseShowMsg(); //顯示baseClass::baseShowMsg 37 instance.showMsg(); //顯示extendClass::showMsg 38 39 baseClass.showMsg.call(instance);//顯示baseClass::showMsg static 40 41 var baseinstance = new baseClass(); 42 baseinstance.showMsg.call(instance);//顯示baseClass::showMsg 43 44 </script>
注意第十五行的是類方法,做者這裏打上static的調試信息,那有點和Java的靜態有點像了啊,類共用,一個模版,js上面代碼這裏專門用來區別第五行的對象方法,兩個輸出的信息不同。第三十九行和四十二行顯示告終果。在上面的extendClass的一個實例instance調用baseClass的對象方法showMsg 也有提到。