码迷,mamicode.com
首页 > 编程语言 > 详细

JavaScript中子类调用父类方法的实现

时间:2018-06-02 23:54:25      阅读:455      评论:0      收藏:0      [点我收藏+]

标签:函数   返回   www   继承   避免   OLE   tps   添加   round   

一、前言

最近在项目中,前端框架使用JavaScript面向对象编程,遇到了诸多问题,其中最典型的问题就是子类调用父类(super class)同名方法,也就是如C#中子类中调用父类函数Base.**。以下摘录了园友幻天芒 JavaScript实现继承的几种方式 的具体介绍以作备忘,但是这几种方式,都不能实现子类调用父类方法。

二、JavaScript实现继承的几种方式

既然要实现继承,那么我们首先得有一个基类,代码如下:

  1. // 定义一个动物类
  2. ????function Animal(name) {
  3. ????????// 属性
  4. ????????this.name = name || ‘Animal‘;
  5. ????????// 实例方法
  6. ????????this.sleep = function () {
  7. ????????????console.log(this.name + ‘正在睡觉!‘);
  8. ????????}
  9. ????}
  10. ????// 原型方法
  11. ????Animal.prototype.eat = function (food) {
  12. ????????console.log(this.name + ‘正在吃:‘ + food);
  13. ????};

1、原型链继承

核心: 将父类的实例作为子类的原型

  1. //定义动物猫
  2. function Cat() {
  3. }
  4. Cat.prototype = new Animal();
  5. Cat.prototype.name = ‘cat‘;
  6. ?
  7. // Test Code
  8. var cat = new Cat();
  9. console.log(cat.name); //cat
  10. cat.eat(‘fish‘); //cat正在吃:fish
  11. cat.sleep(); //cat正在睡觉
  12. console.log(cat instanceof Animal); //true
  13. console.log(cat instanceof Cat); //true

特点:

1.非常纯粹的继承关系,实例是子类的实例,也是父类的实例;

2.父类新增原型方法/原型属性,子类都能访问到;

3.简单,易于实现;

缺点:

1.要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中

2.无法实现多继承;

3.创建子类时,无法向父类构造函数传参;

4.来自原型对象的属性是所有实例所共享;

2、构造继承

核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

  1. function Cat(name) {
  2. ????Animal.call(this);
  3. ????this.name = name || ‘Tom‘;
  4. }
  5. ?
  6. // Test Code
  7. var cat = new Cat();
  8. console.log(cat.name);
  9. console.log(cat.sleep());
  10. console.log(cat instanceof Animal); // false
  11. console.log(cat instanceof Cat); // true

特点:

1. 解决了1中,子类实例共享父类引用属性的问题;

2. 创建子类实例时,可以向父类传递参数;

3. 可以实现多继承(call多个父类对象);

缺点:

1. 实例并不是父类的实例,只是子类的实例;

2. 只能继承父类的实例属性和方法,不能继承原型属性/方法;

3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能;

3、实例继承

核心:为父类实例添加新特性,作为子类实例返回

  1. function Cat(name) {
  2. ????var instance = new Animal();
  3. ????instance.name = name || ‘Tom‘;
  4. ????return instance;
  5. }
  6. ?
  7. // Test Code
  8. var cat = new Cat();
  9. console.log(cat.name);
  10. console.log(cat.sleep());
  11. console.log(cat instanceof Animal); // true
  12. console.log(cat instanceof Cat); // false

特点:

1. 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果;

缺点:

2.无法实现多继承;

4、拷贝继承

  1. function Cat(name) {
  2. ????var animal = new Animal();
  3. ????for (var p in animal) {
  4. ????????Cat.prototype[p] = animal[p];
  5. ????}
  6. ????Cat.prototype.name = name || ‘Tom‘;
  7. }
  8. ?
  9. // Test Code
  10. var cat = new Cat();
  11. console.log(cat.name);
  12. console.log(cat.sleep());
  13. console.log(cat instanceof Animal); // false
  14. console.log(cat instanceof Cat); // true

特点:

1. 支持多继承;

缺点:

1. 效率较低,内存占用高(因为要拷贝父类的属性);

2. 无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到);

5、组合继承

核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

  1. function Cat(name) {
  2. ????Animal.call(this);
  3. ????this.name = name || ‘Tom‘;
  4. }
  5. Cat.prototype = new Animal();
  6. Cat.prototype.constructor = Cat;
  7. ?
  8. // Test Code
  9. var cat = new Cat();
  10. console.log(cat.name);
  11. console.log(cat.sleep());
  12. console.log(cat instanceof Animal); // true
  13. console.log(cat instanceof Cat); // true

特点:

1.弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法;

2.既是子类的实例,也是父类的实例;

3.不存在引用属性共享问题;

4.可传参;

5.函数可复用;

缺点:

1. 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了);

6、寄生组合继承

核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点

  1. function Cat(name){
  2. ????Animal.call(this);
  3. ????this.name = name || ‘Tom‘;
  4. }
  5. (function(){
  6. ????// 创建一个没有实例方法的类
  7. ????var Super = function(){};
  8. ????Super.prototype = Animal.prototype;
  9. ????//将实例作为子类的原型
  10. ????Cat.prototype = new Super();
  11. ????Cat.prototype.constructor = Cat; // 需要修复下构造函数
  12. })();
  13. ?
  14. // Test Code
  15. var cat = new Cat();
  16. console.log(cat.name);
  17. console.log(cat.sleep());
  18. console.log(cat instanceof Animal); // true
  19. console.log(cat instanceof Cat); //true

特点:

1. 堪称完美;

缺点:

1. 实现较为复杂;

三、JavaScript中子类调用父类方法的解决方案

以上的继承方式,都不实现子类调用父类方法, 在重写子类原型函数后,会将继承父类函数给覆盖。

四、总结

附录一、Class基类

  1. //定义最顶级类,用于js继承基类
  2. function Class() { }
  3. Class.prototype.construct = function () { };
  4. Class.extend = function (def) {
  5. ????var subClass = function () {
  6. ????????if (arguments[0] !== Class) { this.construct.apply(this, arguments); }
  7. ????};
  8. ?
  9. ????var proto = new this(Class);
  10. ?
  11. ????var superClass = this.prototype;
  12. ????for (var n in def) {
  13. ????????var item = def[n];
  14. ????????if (item instanceof Function) item.father = superClass;
  15. ????????proto[n] = item;
  16. ????}
  17. ????subClass.prototype = proto;
  18. ?
  19. ????//赋给这个新的子类同样的静态extend方法
  20. ????subClass.extend = this.extend;
  21. ????return subClass;
  22. };

附录二、参考文章

????https://blog.csdn.net/rainxie_/article/details/39991173

JavaScript中子类调用父类方法的实现

标签:函数   返回   www   继承   避免   OLE   tps   添加   round   

原文地址:https://www.cnblogs.com/xyb0226/p/9127424.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!