欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前端開(kāi)發(fā)必須知道的JS之原型和繼承

 更新時(shí)間:2010年07月06日 12:53:39   作者:  
原型和閉包是Js語(yǔ)言的難點(diǎn),此文主要講原型及原型實(shí)現(xiàn)的繼承,在(二)中會(huì)講下閉包,希望對(duì)大家有所幫助。若有疑問(wèn)或不正之處,歡迎提出指正和討論。
一. 原型與構(gòu)造函數(shù)

  Js所有的函數(shù)都有一個(gè)prototype屬性,這個(gè)屬性引用了一個(gè)對(duì)象,即原型對(duì)象,也簡(jiǎn)稱原型。這個(gè)函數(shù)包括構(gòu)造函數(shù)和普通函數(shù),我們講的更多是構(gòu)造函數(shù)的原型,但是也不能否定普通函數(shù)也有原型。譬如普通函數(shù):
復(fù)制代碼 代碼如下:

function F(){
  alert(F.prototype instanceof Object) //true;
}


  構(gòu)造函數(shù),也即構(gòu)造對(duì)象。首先了解下通過(guò)構(gòu)造函數(shù)實(shí)例化對(duì)象的過(guò)程。
復(fù)制代碼 代碼如下:

function A(x){
  this.x=x;
}
var obj=new A(1);


實(shí)例化obj對(duì)象有三步:

  1. 創(chuàng)建obj對(duì)象:obj=new Object();

  2. 將obj的內(nèi)部__proto__指向構(gòu)造他的函數(shù)A的prototype,同時(shí),obj.constructor===A.prototype.constructor(這個(gè)是永遠(yuǎn)成立的,即使A.prototype不再指向原來(lái)的A原型,也就是說(shuō):類的實(shí)例對(duì)象的constructor屬性永遠(yuǎn)指向"構(gòu)造函數(shù)"的prototype.constructor),從而使得obj.constructor.prototype指向A.prototype(obj.constructor.prototype===A.prototype,當(dāng)A.prototype改變時(shí)則不成立,下文有遇到)。obj.constructor.prototype與的內(nèi)部_proto_是兩碼事,實(shí)例化對(duì)象時(shí)用的是_proto_,obj是沒(méi)有prototype屬性的,但是有內(nèi)部的__proto__,通過(guò)__proto__來(lái)取得原型鏈上的原型屬性和原型方法,F(xiàn)ireFox公開(kāi)了__proto__,可以在FireFox中alert(obj.__proto__);

  3. 將obj作為this去調(diào)用構(gòu)造函數(shù)A,從而設(shè)置成員(即對(duì)象屬性和對(duì)象方法)并初始化。

  當(dāng)這3步完成,這個(gè)obj對(duì)象就與構(gòu)造函數(shù)A再無(wú)聯(lián)系,這個(gè)時(shí)候即使構(gòu)造函數(shù)A再加任何成員,都不再影響已經(jīng)實(shí)例化的obj對(duì)象了。此時(shí),obj對(duì)象具有了x屬性,同時(shí)具有了構(gòu)造函數(shù)A的原型對(duì)象的所有成員,當(dāng)然,此時(shí)該原型對(duì)象是沒(méi)有成員的。

  原型對(duì)象初始是空的,也就是沒(méi)有一個(gè)成員(即原型屬性和原型方法)??梢酝ㄟ^(guò)如下方法驗(yàn)證原型對(duì)象具有多少成員。
復(fù)制代碼 代碼如下:

var num=0;
for(o in A.prototype) {
  alert(o);//alert出原型屬性名字
  num++;
}
alert("member: " + num);//alert出原型所有成員個(gè)數(shù)。


  但是,一旦定義了原型屬性或原型方法,則所有通過(guò)該構(gòu)造函數(shù)實(shí)例化出來(lái)的所有對(duì)象,都繼承了這些原型屬性和原型方法,這是通過(guò)內(nèi)部的_proto_鏈來(lái)實(shí)現(xiàn)的。

  譬如

  A.prototype.say=function(){alert("Hi")};

  那所有的A的對(duì)象都具有了say方法,這個(gè)原型對(duì)象的say方法是唯一的副本給大家共享的,而不是每一個(gè)對(duì)象都有關(guān)于say方法的一個(gè)副本。

二. 原型與繼承

  首先,看個(gè)簡(jiǎn)單的繼承實(shí)現(xiàn)。
復(fù)制代碼 代碼如下:

function A(x){
  this.x=x;
}
function B(x,y){
  this.tmpObj=A;
  this.tmpObj(x);
  delete this.tmpObj;
  this.y=y;
}


  第5、6、7行:創(chuàng)建臨時(shí)屬性tmpObj引用構(gòu)造函數(shù)A,然后在B內(nèi)部執(zhí)行,執(zhí)行完后刪除。當(dāng)在B內(nèi)部執(zhí)行了this.x=x后(這里的this是B的對(duì)象),B當(dāng)然就擁有了x屬性,當(dāng)然B的x屬性和A的x屬性兩者是獨(dú)立,所以并不能算嚴(yán)格的繼承。第5、6、7行有更簡(jiǎn)單的實(shí)現(xiàn),就是通過(guò)call(apply)方法:A.call(this,x);

這兩種方法都有將this傳遞到A的執(zhí)行里,this指向的是B的對(duì)象,這就是為什么不直接A(x)的原因。這種繼承方式即是類繼承(js沒(méi)有類,這里只是指構(gòu)造函數(shù)),雖然繼承了A構(gòu)造對(duì)象的所有屬性方法,但是不能繼承A的原型對(duì)象的成員。而要實(shí)現(xiàn)這個(gè)目的,就是在此基礎(chǔ)上再添加原型繼承。


  通過(guò)下面的例子,就能很深入地了解原型,以及原型參與實(shí)現(xiàn)的完美繼承。(本文核心在此^_^)
復(fù)制代碼 代碼如下:

function A(x){
  this.x = x;
}
A.prototype.a = "a";
function B(x,y){
  this.y = y;
  A.call(this,x);
}
B.prototype.b1 = function(){
  alert("b1");
}
B.prototype = new A();
B.prototype.b2 = function(){
  alert("b2");
}
B.prototype.constructor = B;
var obj = new B(1,3);

  這個(gè)例子講的就是B繼承A。第7行類繼承:A.call(this.x);上面已講過(guò)。實(shí)現(xiàn)原型繼承的是第12行:B.prototype = new A();

  就是說(shuō)把B的原型指向了A的1個(gè)實(shí)例對(duì)象,這個(gè)實(shí)例對(duì)象具有x屬性,為undefined,還具有a屬性,值為"a"。所以B原型也具有了這2個(gè)屬性(或者說(shuō),B和A建立了原型鏈,B是A的下級(jí))。而因?yàn)榉讲诺念惱^承,B的實(shí)例對(duì)象也具有了x屬性,也就是說(shuō)obj對(duì)象有2個(gè)同名的x屬性,此時(shí)原型屬性x要讓位于實(shí)例對(duì)象屬性x,所以obj.x是1,而非undefined。第13行又定義了原型方法b2,所以B原型也具有了b2。雖然第9~11行設(shè)置了原型方法b1,但是你會(huì)發(fā)現(xiàn)第12行執(zhí)行后,B原型不再具有b1方法,也就是obj.b1是undefined。因?yàn)榈?2行使得B原型指向改變,原來(lái)具有b1的原型對(duì)象被拋棄,自然就沒(méi)有b1了。

  第12行執(zhí)行完后,B原型(B.prototype)指向了A的實(shí)例對(duì)象,而A的實(shí)例對(duì)象的構(gòu)造器是構(gòu)造函數(shù)A,所以B.prototype.constructor就是構(gòu)造對(duì)象A了(換句話說(shuō),A構(gòu)造了B的原型)。

alert(B.prototype.constructor)出來(lái)后就是"function A(x){...}" 。同樣地,obj.constructor也是A構(gòu)造對(duì)象,alert(obj.constructor)出來(lái)后就是"function A(x){...}" ,也就是說(shuō)B.prototype.constructor===obj.constructor(true),但是B.prototype===obj.constructor.prototype(false),因?yàn)榍罢呤荁的原型,具有成員:x,a,b2,后者是A的原型,具有成員:a。如何修正這個(gè)問(wèn)題呢,就在第16行,將B原型的構(gòu)造器重新指向了B構(gòu)造函數(shù),那么B.prototype===obj.constructor.prototype(true),都具有成員:x,a,b2。

  如果沒(méi)有第16行,那是不是obj = new B(1,3)會(huì)去調(diào)用A構(gòu)造函數(shù)實(shí)例化呢?答案是否定的,你會(huì)發(fā)現(xiàn)obj.y=3,所以仍然是調(diào)用的B構(gòu)造函數(shù)實(shí)例化的。雖然obj.constructor===A(true),但是對(duì)于new B()的行為來(lái)說(shuō),執(zhí)行了上面所說(shuō)的通過(guò)構(gòu)造函數(shù)創(chuàng)建實(shí)例對(duì)象的3個(gè)步驟,第一步,創(chuàng)建空對(duì)象;第二步,obj.__proto__ === B.prototype,B.prototype是具有x,a,b2成員的,obj.constructor指向了B.prototype.constructor,即構(gòu)造函數(shù)A;第三步,調(diào)用的構(gòu)造函數(shù)B去設(shè)置和初始化成員,具有了屬性x,y。雖然不加16行不影響obj的屬性,但如上一段說(shuō),卻影響obj.constructor和obj.constructor.prototype。所以在使用了原型繼承后,要進(jìn)行修正的操作。

  關(guān)于第12、16行,總言之,第12行使得B原型繼承了A的原型對(duì)象的所有成員,但是也使得B的實(shí)例對(duì)象的構(gòu)造器的原型指向了A原型,所以要通過(guò)第16行修正這個(gè)缺陷。

  畢了。

相關(guān)文章

  • 討論javascript(一)工廠方式 js面象對(duì)象的定義方法

    討論javascript(一)工廠方式 js面象對(duì)象的定義方法

    看《javascript高級(jí)程序設(shè)計(jì)》有感
    2009-12-12
  • 面向?qū)ο蟮膉avascript(筆記)

    面向?qū)ο蟮膉avascript(筆記)

    面向?qū)ο蟮膉avascript之學(xué)習(xí)筆記,需要學(xué)習(xí)的朋友可以參考下,腳本之家之前更新了不少這方便的文章。
    2009-10-10
  • JavaScript 工具庫(kù) Cloudgamer JavaScript Library v0.1 發(fā)布

    JavaScript 工具庫(kù) Cloudgamer JavaScript Library v0.1 發(fā)布

    研究了一年多的js,也差不多寫一個(gè)自己的js庫(kù)了。 我寫這個(gè)不算框架,只是一個(gè)小型的js工具庫(kù),所以我用的名字是Library。
    2009-10-10
  • Javascript 對(duì)象的解釋

    Javascript 對(duì)象的解釋

    ECMAScript沒(méi)有像C++,Smalltalk,或者java中那樣規(guī)矩的類,可是它支持通過(guò)執(zhí)行分配空間的代碼來(lái)創(chuàng)建對(duì)象、并初始化對(duì)象所有或者一部分屬性的構(gòu)造器。
    2008-11-11
  • JavaScript 構(gòu)造函數(shù) 面相對(duì)象學(xué)習(xí)必備知識(shí)

    JavaScript 構(gòu)造函數(shù) 面相對(duì)象學(xué)習(xí)必備知識(shí)

    關(guān)于JavaScript構(gòu)造函數(shù),如今出現(xiàn)了很多JavaScript的框架,例如jQuery、Ext等等這些,這些將JavaScript作為一種面向?qū)ο蟮恼Z(yǔ)言進(jìn)行編程,那么JavaScript到底是怎么樣實(shí)現(xiàn)面向?qū)ο蟮囊恍┨卣鞯哪?,首先,我們?lái)看看JavaScript怎么樣來(lái)定義一個(gè)構(gòu)造函數(shù)。
    2010-06-06
  • javascript 面向?qū)ο笕吕砭氈當(dāng)?shù)據(jù)的封裝

    javascript 面向?qū)ο笕吕砭氈當(dāng)?shù)據(jù)的封裝

    JavaScript 是一種非常靈活的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言,它與傳統(tǒng)的強(qiáng)類型的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言(如 C++,Java,C# 等)有很大不同,所以要實(shí)現(xiàn)如 C++、java、C# 當(dāng)中的一些特性就需要換一種思考方式來(lái)解決。
    2009-12-12
  • JavaScript 設(shè)計(jì)模式之組合模式解析

    JavaScript 設(shè)計(jì)模式之組合模式解析

    “組合模式”顧名思意就是將多種實(shí)現(xiàn)組合在一起而達(dá)到牽一處而動(dòng)全身的效果。
    2010-04-04
  • 最新評(píng)論