淺談js中繼承的理解和實現

來源:互聯網
上載者:User

標籤:

一、前言

java、C#等正統物件導向語言都會提供類似extend之類的處理類的繼承的方法,而javascript並沒有提供專門的方法用於繼承,在javascript中使用繼承需要一點技巧。js中執行個體的屬性和行為是由建構函式和原型兩部分組成的,js的繼承也分為這兩部分。下面給大家分享一下在js中如何?繼承,講的不對的地方望大家指正!

二、繼承建構函式中的屬性和行為

我們定義兩個類Animal和Bird類,來實現js中類的繼承。

//定義Animal類            function Animal(name){                this.name = name;                this.type = ‘animal‘;            }            //Animal原型添加say方法            Animal.prototype.say = function(){                alert("I‘m a(an) "+ this.type +", my name is "+ this.name);            };

接下來定義Bird類

//定義Bird類function Bird(name){    this.name = name;    this.type = ‘bird‘;}Bird.prototype = {};

我們先讓Bird類繼承Animal的建構函式中的屬性和行為,代碼清單如下

//定義Animal類function Animal(name){    this.name = name;    this.type = ‘animal‘;}//Animal原型添加say方法Animal.prototype = {    say : function(){        alert("I‘m a(an) "+ this.type +", my name is "+ this.name);    }};//定義Bird類function Bird(name){    this.name = name;    this.type = ‘animal‘;}Bird.prototype = {};//執行個體化Bird類var canary = new Bird(‘yinwu‘);alert(canary.type);

程式運行正常,但看不出繼承,因為在Bird類的建構函式中是將Animal的屬性和行為複製了一份。同時,缺點也很明顯,如果Animal類的建構函式有任何改動,Bird類也要手動的同步改動,同樣一份代碼,複製在程式中不同地方,違反了DRY原則,降低了代碼的可維護性。需要改進,改進後的代碼清單如下:

//定義Animal類function Animal(name){    this.name = name;    this.type = ‘animal‘;}//Animal原型添加say方法Animal.prototype = {    say : function(){        alert("I‘m a(an) "+ this.type +", my name is "+ this.name);    }};//定義Bird類function Bird(name){    Animal.call(this, name);}Bird.prototype = {};//執行個體化Bird類var canary = new Bird(‘yinwu‘);alert(canary.type);//animal

我們把Bird類改為了Animal.call(this, name);,也就是通過call()方法實現讓Animal內部的this指向Bird類的執行個體。改進後的代碼就實現了建構函式的屬性和行為的繼承,最後alert(canary.type)彈出的資訊為animal。

三、原型的繼承

由繼承我們知道,繼承後子類擁有了父類同樣的屬性和行為,那麼能否將Animal類的原型直接傳給Bird類的原型呢?請看如下代碼清單:

//定義Animal類function Animal(name){    this.name = name;    this.type = ‘animal‘;}//Animal原型添加say方法Animal.prototype = {    say : function(){        alert("I‘m a(an) "+ this.type +", my name is "+ this.name);    }};//定義Bird類function Bird(name){    Animal.call(this, name);}Bird.prototype = Animal.prototype;//執行個體化Bird類var canary = new Bird(‘yinwu‘);canary.say();//I‘m a(an) animal, my name is yinwu

通過把Animal類的原型直接傳給Bird類的原型,Bird類擁有了Animal原型中的say行為。如果給Bird類的原型添加fly行為,結果會如何呢?如代碼清單:

//定義Animal類function Animal(name){    this.name = name;    this.type = ‘animal‘;}//Animal原型添加say方法Animal.prototype = {    say : function(){        alert("I‘m a(an) "+ this.type +", my name is "+ this.name);    }};//定義Bird類function Bird(name){    Animal.call(this, name);}Bird.prototype = Animal.prototype;//Bird類原型添加fly方法Bird.prototype.fly = function(){    alert("I‘m flying more high ");}//執行個體化Bird類var canary = new Bird(‘yinwu‘);canary.say();//I‘m a(an) animal, my name is yinwucanary.fly();//I‘m flying more highvar pig = new Animal(‘xiaozhu‘);pig.fly();//I‘m flying more high

程式運行你會發現Animal類也獲得了fly行為,pig對象調用fly行為彈出I‘m flying more high的提示資訊,我們只給Bird類添加fly行為,為什麼Animal類也獲得了fly行為呢?原因在於”Bird.prototype = Animal.prototype;”這句代碼,因為prototype原型本質上是hash對象,賦值時會進行傳址,也就是說Bird.prototype原型和Animal.prototype原型指向同一記憶體位址,對Bird.prototype原型添加fly行為也就相當於為Animal.prototype原型添加了fly行為,這就是pig會fly的原因。如何對代碼進行改進呢?請看如下代碼清單:

//定義Animal類function Animal(name){    this.name = name;    this.type = ‘animal‘;}//Animal原型添加say方法Animal.prototype = {    say : function(){        alert("I‘m a(an) "+ this.type +", my name is "+ this.name);    }};//定義Bird類function Bird(name){    Animal.call(this, name);}Bird.prototype = new Animal();Bird.prototype.constructor = Bird;//Bird類原型添加fly方法Bird.prototype.fly = function(){    alert("I‘m flying more high ");}//執行個體化Bird類var canary = new Bird(‘yinwu‘);canary.say();//I‘m a(an) animal, my name is yinwucanary.fly();//I‘m flying more highvar pig = new Animal(‘xiaozhu‘);pig.fly();//報錯

與前一代碼清單相比,把”Bird.prototype = Animal.prototype;”這句代碼,改成了”Bird.prototype = new Animal(); Bird.prototype.constructor = Bird;”,這兩句什麼意思呢? ”Bird.prototype = new Animal();”意思是Bird.prototype原型作為Animal類的執行個體,那麼Bird原型對象中包含了一個指向Animal原型對象的指標;“Bird.prototype.constructor = Bird;”意思是因為“Bird.prototype = new Animal();”時,Bird.prototype.constructor指向了Animal原型對象,將其糾正重新指向Bird。代碼運行後你會發現pig.fly()會報錯,此fly()行為undefined,那是因為Animal原型中沒有fly行為。到此我們就實現了Bird類對Animal類的原型繼承。

四、js繼承的封裝

前面二、三小節中分別實現了建構函式和原型的屬性和行為的繼承,這節中我們將js中實現繼承的過程進行封裝,向外提供介面調用。請看下列代碼:

//js繼承封裝成函數並提供介面function extend(subClass, superClass){    var F = function(){};    F.prototype = superClass.prototype;//F.prototype 原型對象和superClass.prototype原型對象指向同一記憶體位址    subClass.prototype = new F();//subClass.prototype作為F類的執行個體    subClass.prototype.constructor = subClass;//將subClass.prototype.constructor重新指向subClass    subClass.superclass = superClass.prototype;//subClass類中定義superclass屬性使其指向superClass.prototype    if(superClass.prototype.constructor == Object.prototype.constructor){        superClass.prototype.constructor = superClass;    }}//定義Animal類function Animal(name){    this.name = name;    this.type = ‘animal‘;}//Animal原型添加say方法Animal.prototype.say = function(){    alert("I‘m a(an) "+ this.type +", my name is "+ this.name);};//定義Bird類function Bird(name){    this.constructor.superclass.constructor.apply(this, arguments);//通過apply方法繼承Animal類中的屬性和行為    this.type = ‘bird‘;}//實現對Animal繼承extend(Bird, Animal);Bird.prototype.fly = function(){    alert("I‘m flying more high ");};//執行個體化var canary = new Bird(‘yinwu‘);canary.say();//I‘m a(an) animal, my name is yinwucanary.fly();//I‘m flying more high

通過上述方法將js中的繼承封裝在函數中,要用到繼承時直接調用即可。

此文章發布在本人部落格園changjianqiu,如需轉載本文,請註明來源: http://www.cnblogs.com/changjianqiu/

淺談js中繼承的理解和實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.