1.prototype屬性在js中模拟了父類的角色,在js中展現面向對象的思想
首先讓我們來看兩個demo:
demo1:
function Person(name,sex)
{this.name=name;this.sex=sex;}
Person.prototype.age=12;
Person.prototype.print=function(){alert(this.name+"_"+this.sex+"_"+this.age);};
var p1 = new Person("name1","male");
var p2=new Person("name2","male");
p1.print();//name1_male_12
p2.print();//name2_male_12
Person.prototype.age=18;
p1.print();//name1_male_18
p2.print();//name2_male_18
demo2:
function Person(name,sex){this.name=name;this.sex=sex;}
Person.prototype.age=12;
Person.ptototype.print=function(){alert(this.name+"_"+this.sex+"_"+this.age);}
var p1=new Person("name1","male"); //p1的age屬性繼承了Person類的父類(即prototype對象)
var p2=new Person("name2","male");
p1.print();//name1_male_12
p2.print();//name2_male_12
p1.age=34 //改變p1執行個體的age屬性
p1.print();//name1_male_34
p2.print();//name2_male_12
Person.prototype.age=22;//改變Person類的超類的age屬性
p1.print();//name1_male_34(p1的age屬性沒有随着prototype屬性的改變而改變)
p2.print();//name2_male_22(p2的age屬性發生了改變)
p1.print()=function(){alert("i am p1")};
p1.print();//I am p1(p1的方法發生了改變)
p2.print();//name2_male_22(p2的方法并沒有改變)
Person.prototype.print=function(){alert("new print method")};//改變超類的方法
p1.print();//I am p1(p1的print方法仍舊是自己的方法 )
p2.print();//newprint method(p2的print方法随着超類的方法改變而改變)
js中對象的prototype屬性相當于java中的static變量,可以被這個類下的所有對象公用。
從基礎上來分析:
1.普通函數與構造函數
調用構造函數:new function_name();
調用普通函數:function_name();
在函數中有一個this對象,this始終代表該函數的調用者。
如果是構造函數,this就是構造出來的新對象。
如果是普通函數,this就是 window 對象。
如果使用new 關鍵字調用,那麼函數的 return 語句不再起作用,因為這時還回的是 this 對象。
function Boo(name){
this.name=name;
this.whatAreYou=function(){
return 'I am a '+ this.name;
};
}
var obj = new Boo("obj");
Boo.name = "Boo";
alert(obj.name + "\n" + Boo.name);
建立對象最好采用下面方式
用構造函數定義對象的成員屬性屬性,用原型方式定義對象的成員方法。
這樣的好處是:每個對象都共享一個方法,并且都具有自己獨立的屬性執行個體。
function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","John");
}
Car.prototype.showColor = function() {
alert(this.color);
};
var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",3,25);
oCar1.drivers.push("Bill");
alert(oCar1.drivers); //輸出 "Mike,John,Bill"
alert(oCar2.drivers); //輸出 "Mike,John"
js中的this的用法:
1、全局變量用法,純粹函數調用。
function test() {
this.x = 1;
alert(x);
}
test();
var x = 1;
function test() {
alert(this.x);
}
test();//1
var x = 1;
function test() {
this.x = 0;
}
test();
alert(x);//0
2. 作為方法調用,那麼this就是指這個上級對象。
function test() {
alert(this.x);
}
var o = {};
o.x = 1;
o.m = test;
o.m(); //1
3、 作為構造函數調用。所謂構造函數,就是生成一個新的對象。這時,這個this就是指這個對象。
function test() {
this.x = 1;
}
var o = new test();
alert(o.x);//1
4、 apply調用
this指向的是apply中的第一個參數。
var x = 0;
function test() {
alert(this.x);
}
var o = {};
o.x = 1;
o.m = test;
o.m.apply(); //0
o.m.apply(o);//1
當apply沒有參數時,表示為全局對象。是以值為0。
------this指針代表的是執行目前代碼的對象的所有者。
js原型鍊和prototype的深入了解:
說到prototype,就不得不先說下new的過程。
<script type="text/javascript">
var Person = function () { };
var p = new Person();
</script>
我們可以把new的過程拆分成以下三步:
<1> var p={}; 也就是說,初始化一個對象p。
<2> p.__proto__=Person.prototype;
<3> Person.call(p);也就是說構造p,也可以稱之為初始化p。
關鍵在于第二步,我們來證明一下:
<script type="text/javascript">
2 var Person = function () { };
3 var p = new Person();
4 alert(p.__proto__ === Person.prototype);
5 </script>
這段代碼會傳回true。說明我們步驟2的正确。
那麼__proto__是什麼?我們在這裡簡單地說下。每個對象都會在其内部初始化一個屬性,就是__proto__,當我們通路一個對象的屬性 時,如果這個對象内部不存在這個屬性,那麼他就會去__proto__裡找這個屬性,這個__proto__又會有自己的__proto__,于是就這樣 一直找下去,也就是我們平時所說的原型鍊的概念。
按照标準,__proto__是不對外公開的,也就是說是個私有屬性,但是Firefox的引擎将他暴露了出來成為了一個共有的屬性,我們可以對外通路和設定。
<script type="text/javascript">
2 var Person = function () { };
3 Person.prototype.Say = function () {
4 alert("Person say");
5 }
6 var p = new Person();
7 p.Say();
8 </script>
那就讓我們看下為什麼p可以通路Person的Say。
首先var p=new Person();可以得出p.__proto__=Person.prototype。那麼當我們調用p.Say()時,首先p中沒有Say這個屬性, 于是,他就需要到他的__proto__中去找,也就是Person.prototype,而我們在上面定義了 Person.prototype.Say=function(){}; 于是,就找到了這個方法。
<script type="text/javascript">
02 var Person = function () { };
03 Person.prototype.Say = function () {
04 alert("Person say");
05 }
06 Person.prototype.Salary = 50000;
07 var Programmer = function () { };
08 Programmer.prototype = new Person();
09 Programmer.prototype.WriteCode = function () {
10 alert("programmer writes code");
11 };
12 Programmer.prototype.Salary = 500;
13 var p = new Programmer();
14 p.Say();
15 p.WriteCode();
16 alert(p.Salary);
17 </script>
好,算清楚了之後我們來看上面的結果,p.Say()。由于p沒有Say這個屬性,于是去p.__proto__,也就是 Programmer.prototype,也就是p1中去找,由于p1中也沒有Say,那就去p.__proto__.__proto__,也就是 Person.prototype中去找,于是就找到了alert(“Person say”)的方法。
其餘的也都是同樣的道理。
這也就是原型鍊的實作原理。
最後,其實prototype隻是一個假象,他在實作原型鍊中隻是起到了一個輔助作用,換句話說,他隻是在new的時候有着一定的價值,而原型鍊的本質,其實在于__proto__!