天天看點

JS中prototype屬性的了解

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__!