標籤:一點 輸出 存在 運行時 測試 asc for log example
1、prototype的定義
javascript中的每個對象都有prototype屬性,Javascript中對象的prototype屬性的解釋是:返回物件類型原型的引用。
每一個建構函式都有一個屬性叫做原型。這個屬性非常有用:為一個特定類聲明通用的變數或者函數。
你不需要顯式地聲明一個prototype屬性,因為在每一個建構函式中都有它的存在。你可以看看下面的例子:
function Test(){}alert(Test.prototype); // 輸出 "Object"
1.1、 原型法設計模式
原型法的主要思想是,現在有1個類A,我想要建立一個類B,這個類是以A為原型的,並且能進行擴充。我們稱B的原型為A。
1.2、javascript的方法可以分為三類:
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.3、給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.4、用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()); // 輸出 200000alert(boss2.getSalary()); // 輸出 100000alert(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
在外部不能通過prototype改變自訂類型的屬性或方法。該例子可以看到:調用的屬性和方法仍是最初定義的結果。即當原型方法和對象方法在調用相同的屬性和函數時,會執行對象方法裡面的屬性和函數。
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.5、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.6、對象方法與通過new建立對象的重要區別
這個區別就是function定義的方法(對象方法)有一個prototype屬性,使用new產生的對象就沒有這個prototype屬性。也就是prototype屬性是對象方法或者構造方法的專有屬性。 prototype屬性又指向了一個prototype對象,注意prototype屬性與prototype對象是兩個不同的東西,要注意區別。在prototype對象中又有一個constructor屬性,這個constructor屬性同樣指向一個constructor對象,而這個constructor對象恰恰就是這個function函數本身。如下所示:
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) {...};
最後,下面這個代碼如果理解清晰,那麼這篇文章說的就已經理解了:
<script type="text/javascript">function baseClass(){ this.showMsg = function() { alert("baseClass::showMsg"); } this.baseShowMsg = function() { alert("baseClass::baseShowMsg"); }}baseClass.showMsg = function(){ alert("baseClass::showMsg static");}function extendClass(){ this.showMsg =function () { alert("extendClass::showMsg"); }}extendClass.showMsg = function(){ alert("extendClass::showMsg static")}extendClass.prototype = new baseClass();var instance = new extendClass();instance.showMsg(); //顯示extendClass::showMsginstance.baseShowMsg(); //顯示baseClass::baseShowMsginstance.showMsg(); //顯示extendClass::showMsgbaseClass.showMsg.call(instance);//顯示baseClass::showMsg staticvar baseinstance = new baseClass();baseinstance.showMsg.call(instance);//顯示baseClass::showMsg</script> 總結:本文對在javascript中經常出現且難以理解的prototype屬性,在含義,使用方法(給prototype添加屬性,用prototype給對象添加函數),在添加函數且調用內容函數過程中遇到的一些問題提供了相應的解決方案等方面做了相關的解釋,希望對大家有協助,喜歡的話,記得動動手指點點推薦哦!
js中Prototype屬性解釋及常用方法