Javascript繼承機制總結

來源:互聯網
上載者:User
Javascript繼承  
一直想對Javascript再次做一些總結,正好最近自己寫了一個小型Js UI庫,總結了一下Js的繼承機制,在網上也看了一些前輩們部落格裡的總結,感覺分析不是特別全面。這裡僅僅是把自己的學習體會拿出來分享一下,希望對大家學習Javascript有所協助。  

Javascript本身是從Perl語言的文法演變而來的,本質上是指令碼語言,隨著版本的更新逐漸加入的對物件導向的類比。我認為Js的物件導向類比總體上做得還是不錯的,因為我們不能盲從任何一種理念,不能純粹的為了OOP而OOP,我們需要抓住的是物件導向的好處到底是什嗎?為了這些優點去OOP,才是最明智的選擇,所以說Js做得還不錯。  

Js的繼承在很多書裡面細緻的分了很多種類型和實現方式,大體上就是兩種:對象冒充、原型方式。這兩種方式各有優點和缺陷,這裡我先列舉出來,再從底層分析區別:  

(一)對象冒充  

JScript code
function A(name){    this.name = name;    this.sayHello = function(){alert(this.name+” say Hello!”);};}function B(name,id){    this.temp = A;    this.temp(name);        //相當於new A();    delete this.temp;        //防止在以後通過temp引用覆蓋超類A的屬性和方法     this.id = id;        this.checkId = function(ID){alert(this.id==ID)};}

當構造對象B的時候,調用temp相當於啟動A的建構函式,注意這裡的上下文環境中的this對象是B的執行個體,所以在執行A建構函式指令碼時,所有A的變數和方法都會賦值給this所指的對象,即B的執行個體,這樣子就達到B繼承了A的屬性方法的目的。之後刪除臨時引用temp,是防止維護B中對A的類對象(注意不是執行個體對象)的引用更改,因為更改temp會直接導致類A(注意不是類A的對象)結構的變化。  

我們看到了,在Js版本更新的過程中,為了更方便的執行這種上下文this的切換以達到繼承或者更加廣義的目的,增加了call和apply函數。它們的原理是一樣的,只是參數不同的版本罷了(一個可變任意參數,一個必須傳入數組作為參數集合)。這裡就以call為例子,解釋一下用call實現的對象冒充繼承。  

JScript code
function Rect(width, height){    this.width = width;    this.height = height;    this.area = function(){return this.width*this.height;};}function myRect(width, height, name){    Rect .call(this,width,height);    this.name = name;    this.show = function(){    alert(this.name+” with area:”+this.area());    }}

關於Call方法,官方解釋:調用一個對象的一個方法,以另一個對象替換當前對象。  
call (thisOb,arg1, arg2…)  

這也是一種對象冒充的繼承,其實在call方法調用的時候發生的事情也是上下文環境變數this的替換,在myRect函數體中this肯定是指向類myRect對象的執行個體了,然而用這個this作為上下文環境變數調用名字叫Rect方法,即類Rect的建構函式。於是此時調用Rect時候對this的賦值屬性和方法都實際上是對一個myRect的對象進行。所以說儘管call和apply並不是僅僅為了繼承而新增的方法,但用它們可以類比繼承。  

對象冒充繼承就是這麼一回事,它可以實現多重繼承,只要重複做這一套賦值的流程就可以了。不過目前真正大規模使用得並不多,為什麼呢?因為它有一個明顯的效能缺陷,這就要說道OO的概念了,我們說對象是成員+成員方法的集合,構造對象執行個體的時候,這些執行個體只需要擁有各自的成員變數就可以了,成員方法只是一段對變數操作的可執行文本地區而已,這段地區不用為每個執行個體而複製一份,所有的執行個體都可以共用。現在回到Js利用對象冒充類比的繼承裡,所有的成員方法都是針對this而建立的,也就是所所有的執行個體都會擁有一份成員方法的副本,這是對記憶體資源的一種極度浪費。其它的缺陷比如說對象冒充無法繼承prototype域的變數和方法就不用提了,筆者認為前一個致命缺陷就已經足夠。不過,我們還是需要理解它,特別是父類的屬性和方法是如何繼承下來的原理,對於理解Js繼承很重要。  

(二)原型方式  
第二種繼承方式是原型方式,所謂原型方式的繼承,是指利用了prototype或者說以某種方式覆蓋了prototype,從而達到屬性方法複製的目的。其實現方式有很多中,可能不同架構多少會有一點區別,但是我們把握住原理,就不會有任何不理解的地方了。看一個例子(某一種實現):  

JScript code
function Person(){    this.name = “Mike”;    this.sayGoodbye = function(){alert(“GoodBye!”);};}Person.prototype.sayHello = function(){alert(”Hello!”);};function Student(){}Student.prototype = new Person();

關鍵是對最後一句Student原型屬性賦值為Person類構造的對象,這裡筆者解釋一下父類的屬性和方法是如何copy到子類上的。Js對象在讀取某個對象屬性的時候,總是先查看自身域的屬性列表,如果有就返回否則去讀取prototype域(每個對象共用構造對象的類的prototype域所有屬性和方法),如果找到就返回,由於prototype可以指向別的對象,所以Js解譯器會遞迴的去尋找prototype域指向對象的prototype域,直到prototype為本身,尋找變成了一種迴圈,就停止,此時還沒找到就成undefined了。  

這樣看來,最後一句發生的效果就是將父類所有屬性和方法串連到子類的prototype域上,這樣子類就繼承了父類所有的屬性和方法,包括name、sayGoodbye和sayHello。這裡與其把最後一句看成一種賦值,不如理解成一種指向關係更好一點。這種原型繼承的缺陷也相當明顯,就是繼承時父類的建構函式時不能帶參數,因為對子類prototype域的修改是在聲明子類對象之後才能進行,用子類建構函式的參數去初始化父類屬性是無法實現的,如下所示:  

JScript code
function Person(name){    this.name = name;}function Student(name,id){    this.id = id;}Student.prototype = new Person(this.name);

兩種繼承方式已經講完了,如果我們理解了兩種方式下子類如何把父類的屬性和方法“抓取”下來,就可以自由組合各自的利弊,來實現真正合理的Js繼承。下面是個人總結的一種綜合方式:  

JScript code
function Person(name){    this.name = name;}Person.prototype.sayHello = function(){alert(this.name+“say Hello!”);};function Student(name,id){    Person.call(this,name);    this.id = id;}Student.prototype = new Person();Student.prototype.show = function(){    alert(“Name is:”+ this.name+” and Id is:”+this.id);}

總結就是利用對象冒充機制的call方法把父類的屬性給抓取下來,而成員方法盡量寫進被所有對象執行個體共用的prototype域中,以防止方法副本重複建立。然後子類繼承父類prototype域來抓取下來所有的方法。如想徹底理清這些調用鏈的關係,推薦大家多關注Js中prototype的constructor和對象的constructor屬性,這裡就不多說了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.