javascript代码实例教程-javascript继承之借用构造函数与原型

发布时间:2019-02-07 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了javascript代码实例教程-javascript继承之借用构造函数与原型脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
小宝典致力于为广大程序猿(媛)提供高品质的代码服务,请大家多多光顾小站,小宝典在此谢过。    在js中,关于继承只有利用构造函数和原型链两种来现实。以前所见到的种种方法与模式,只不过是变种罢了。

 

借用构造函数

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// 一个动物类,包含名字和性别属性

function Animal (name, sex) {

    this.name = name;

    this.sex = sex;    

    this.getName = function(){  

       return this.name;    

    };       

}

 

// Cat类继承Animal基类,并且拥有额外的属性

function Cat (name, sex, hasLegs) {

    this.hasLegs = hasLegs;

    Animal.apply(this, arguments);// 借用Animal的构造器

}

 

// Dog类继承Animal基类,并且拥有与Cat类不一样的额外的属性

function Dog (name, sex, otherFeatures) {

    this.otherFeatures= otherFeatures;

    Animal.apply(this, arguments); // 借用Animal的构造器

 

}

     借用构造函数的优点就是能够复用代码;缺点就是它不能继承基类的原型,以及部分代码累赘。像Animal类中的getName方法,本该有一个就可以了,但是每次调用其构造器都会开辟新的空间来存放这个方法。如果把这些共有的属性或者方法放入原型链中,就不会需要每个实例都有一个这样的属性或者方法,而是大家共用一个模板。

 

构造函数与原型并用

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// 重新定义动物类,

function Animal (name, sex) {

    this.name = name;

    this.sex = sex;    

}

 

// 提取公共的方法或者属性放入原型链中

Animal.PRototyPE.getName = function (){ return this.name;}

 

//Cat类不变,修改Cat的原型链,使其指向基类的原型

Cat.prototype = Animal.prototype;

 

//Dog类不变,修改Dog的原型链,使其指向基类的原型

Dog.prototype = Animal.prototype;

 测试代码1

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

// 分别new一个对象

VAR cat = new Cat('咪咪', 'female', true),

 

     dog = new Dog('汪汪', ';male', null);

 

// 功能已实现

console.LOG(cat.getName(),dog.getName()); // 咪咪 汪汪

 

// 新的问题1

console.log(cat instanceof Cat, dog instanceof Cat); // true true 现在猫狗不分了

 

/*原因是在改变各个具体子类的原型是,它们的构造器都指向了基类,它们拥有同一个构造器。

如果修改某个子类的原型constructor,必然会影响到其它子类*/

 

// 新问题2。如果现在Cat类的getName逻辑有变,不能修改基类的原型。现作出如下改动

function Cat (name, sex, hasLegs) {

    this.hasLegs = hasLegs;

    Animal.apply(this, arguments);

     // 新的逻辑

    this.getName = function (){

        return this.name+','+this.sex;

    }   

}

 

//但是这样代码又不能达到复用,因为每个Cat实例都有一个getName方法。

/*如何解决上述问题呢,也许你想到了——原型【链】。突出个链字,链说明是一节一节的,如果

我们在子类与基类原型中间再加一节,不就完事了么*/

 

//定义一个空函数来做这个节点

function o (){}

 

// 让‘空’节点指向基类的原型,Cat类再指向空节点

o.prototype = Animal.prototype;

Cat.prototype = new o();

// 重置Cat的构造器指针

Cat.prototype.constructor = Cat;

 

o.prototype = Animal.prototype;

Dog.prototype = new o();

Dog.prototype.constructor = Dog;

 完整的代码

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

// 一个动物类,包含名字和性别属性

function Animal (name, sex) {

  this.name = name;

  this.sex = sex;

 

}

// 提取公共的方法或者属性放入原型链中

Animal.prototype.getName = function (){ return this.name;}

 

function o (){}

var oCat = new o();    

// 修改Cat类的getName逻辑

oCat.getName = function (){return this.name+','+this.sex;}

 

o.prototype = Animal.prototype;

Cat.prototype = oCat;

//重值Cat构造器指针

Cat.prototype.constructor = Cat;

// 同上。并且这三行代码的顺序不能随意改动

o.prototype = Animal.prototype;

Dog.prototype = new o();

Dog.prototype.constructor = Dog;

 

 

// Cat类继承Animal基类,并且拥有额外的属性

function Cat (name, sex, hasLegs) {

  this.hasLegs = hasLegs;

  Animal.apply(this, arguments);

}

 

// Dog类继承Animal基类,并且拥有与Cat类不一样的额外的属性

function Dog (name, sex, otherFeatures) {

  this.otherFeatures= otherFeatures;

  Animal.apply(this, arguments);

 

}

 

var cat = new Cat('咪咪', 'female', true),

 

dog = new Dog('汪汪', 'male', null);

 

// 功能正常,代码也达到进一步复用

console.log(cat.getName(), dog.getName());

// 现在猫是猫,狗是狗了

console.log(cat instanceof Cat, dog instanceof Cat);

// 两个子类的构造器也是对的了

console.log(cat.constructor, dog.constructor);

 现在似乎完整了,可是好像还是有些遗憾。如同被妹子拒了一样:你人很好,我们还是做朋友吧。言外之意就是还没好到让妹子想跟你在一起的程度。那么哪里不够呢?现在只有两个子类,如果有几十个的话,还是要做很多重复的工作;如果又有一个机械的基类,又要做同样的事情。那么,我们可以把这个继承的方法写成面向对象的形式么?答案是:可以滴。

 

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

// 将继承的实现细节用函数包裹起来,classPropers是需要覆盖的属性和方法

 

function inherIT(classPropers){

     var o = function (){}, // 空函数用做空节点

          parent = this, // 这里的this代表基类构造器

          child = function(){}, // 返回一个子类

          hasOwnConstructor = false; // 是否拥有自己的构造器

     if(typeof classPropers === 'object'

        && classPropers.hasOwnProperty('constructor')){

         //如果有构造器属性,则覆盖构造器

         child = function (){

              classPropers.constructor.apply(this,arguments);    

         }

         hasOwnConstructor = true;

          

     }else{

         // 否则使用基类的构造器

          child = function(){

               parent.apply(this, arguments);

          }

     }

     o.prototype = parent.prototype; 

     child.prototype = new o(); 

     if(hasOwnConstructor){

        // 重置构造器指针

        child.prototype.constructor = classPropers.constructor

     }

     if(classPropers){

         /*$.extend是jq函数,这里不再实现。如果classPropers与基类有相同的方法,则会‘覆盖’

         基类的方法*/

         $.extend(child.prototype, classPropers);      

     }

     // 继承基类的静态方法,这样子类还可以被继承

     $.extend(child, parent);

     child.__super__ = parent.prototype; // 以万一以后还要调用基类相同方法

 

     return child;

 

}         

 完整测试代码2

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

// 一个动物类,包含名字和性别属性

    function Animal (name, sex) {

        this.name = name;

        this.sex = sex;

   

    }

    Animal.prototype = {

        getName: function(){ return this.name;},

        getSex: function(){ return this.sex;}

    };

    function inherit(classPropers){

     var o = function (){}, // 空函数用做空节点

          parent = this, // 这里的this代表基类构造器

          child = function(){}, // 返回一个子类

          hasOwnConstructor = false; // 是否拥有自己的构造器

     if(typeof classPropers === 'object'

        && classPropers.hasOwnProperty('constructor')){

         //如果有构造器属性,则覆盖构造器

         child = function (){

              classPropers.constructor.apply(this,arguments);   

         }

         hasOwnConstructor = true;

           

     }else{

         // 否则使用基类的构造器

          child = function(){

               parent.apply(this, arguments);

          }

     }

     o.prototype = parent.prototype;

     child.prototype = new o();

     if(hasOwnConstructor){

        // 重置构造器指针

        child.prototype.constructor = classPropers.constructor

     }

     if(classPropers){

         /*$.extend是jQ函数,这里不再实现。如果classPropers与基类有相同的方法,则会‘覆盖’

         基类的方法*/

         $.extend(child.prototype, classPropers);     

     }

     // 继承基类的静态方法,这样子类还可以被继承

     $.extend(child, parent);

     child.__super__ = parent.prototype; // 以防万一以后还要调用基类相同方法

  

     return child;

  

    }  

    Animal.inherit = inherit;

 

    var Cat = Animal.inherit({sayHi:function(){console.log('喵喵...')}}),

    cat = new Cat('咪咪', '不告诉你');

 

    console.log(cat.getName(),cat.getSex());

 

  var Dog = Animal.inherit({

                constructor:function(name){ 

                  this.name = name;

                  console.log('我有自己的工厂(构造器)');

                }

            }),

  dog = new Dog('我为自己代言');

  console.log(dog.getName(),dog.constructor);

 

  // 老虎小时候就是猫,不信,我有证据如下。

  var Tiger = Cat.inherit({constructor:function(){console.log('出来一声吼啊!喵喵......咋变猫叫了呢?wuwu...')}}),

  tiger = new Tiger();

 

  tiger.sayHi();

 记得引用jQuery或者自己实现$.extend函数。

觉得可用,就经常来吧! 脚本宝典 欢迎评论哦! js脚本,巧夺天工,精雕玉琢。小宝典献丑了!

脚本宝典总结

以上是脚本宝典为你收集整理的javascript代码实例教程-javascript继承之借用构造函数与原型全部内容,希望文章能够帮你解决javascript代码实例教程-javascript继承之借用构造函数与原型所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。