zoukankan      html  css  js  c++  java
  • JavaScript面向对象轻松入门之多态(demo by ES5、ES6、TypeScript)

      多态(Polymorphism)按字面的意思就是“多种状态”,同样的行为(方法)在不同对象上有不同的状态。
      在OOP中很多地方都要用到多态的特性,比如同样是点击鼠标右键,点击快捷方式、点击桌面空白处、点击任务栏等弹出的菜单都是不同的。

    方法重写(override):

      即子类定义一个与父类名字相同的方法,以此覆盖父类方法,以此来实现不同的功能。

     1     function Animal(){}
     2     var AnimalP = Animal.prototype;
     3     AnimalP.eat = function(food){
     4         console.log('这个动物正在吃' + food);
     5     };
     6 
     7     function Snake(){}
     8     var SnakeP = extend(Snake,Animal);//extend函数请看上一节
     9     /*snake没有对eat方法重写,继承的父类eat()方法*/
    10     function Dog(){}
    11     var DogP = extend(Dog,Animal);
    12     DogP.eat = function(food){
    13         /*对eat()方法重写*/
    14         /*上一章讲过,也可以在这里通过 Animal.eat.call(this,food)调用父方法;*/
    15         console.log("这只狗正在吃"+food);
    16     };
    17 
    18     function Cat(){}
    19     var CatP = extend(Cat,Animal);
    20     CatP.eat = function(food){
    21         console.log("这只猫正在吃"+food);
    22     };
    23     var snake = new Snake();
    24     snake.eat('老鼠');//log:这个动物正在吃老鼠
    25     var dog = new Dog();
    26     dog.eat('骨头');//log:这只狗正在吃骨头
    27     var cat = new Cat();
    28     cat.eat('鱼');//log:这只猫正在吃鱼

    抽象类(abstract class):

      上面的代码中,Snake类没有实现自己的eat()方法,但有的时候我们希望子类一定要有某个方法(抽象方法),这样可以规范子类的行为,这时候就要用到抽象类,
      ES5、ES6都没有抽象类的概念的,所以我们只能通过模拟来实现,让我们接着上面的代码,假如我们要把Animal的eat()方法定义为抽象方法:

    1     AnimalP.eat = function(food){
    2         /*定义抽象方法(虚函数),如果子类没有重写这个方法,在执行这方法的时候就会抛出错误*/
    3         throw '"' + this.constructor.name + "'类没有eat()方法";
    4     };
    5     function Snake(){}
    6     var SnakeP = extend(Snake,Animal);
    7     var snake = new Snake();
    8     snake.eat('老鼠');//throw:"Snake'类没有eat()方法

    方法重载(overload):

      我们一定写过这样的函数,根据传入的参数不一样(类型、参数个数),方法的运行结果也不一样:

    1 var run = function(speed){
    2         if(typeof speed == 'number'){
    3             console.log('跑的速度有' + speed + 'm/s');
    4         }else if(typeof speed == 'string'){
    5             console.log('跑的速度有' + speed);
    6         }
    7     }
    8     run(15);//log:跑的速度有15m/s
    9     run('20KM/h');//log:跑的速度有20KM/h

       但上面这样写明显代码难维护,可以把run方法作为一个接口,根据参数的类型执行不同方法,用在类中就向下面一样:

     1     function Dog(){}
     2     var DogP = Dog.prototype;
     3     DogP.run = function(speed){
     4         if(typeof speed == 'number'){
     5             this._runNumber(speed);
     6         }else if(typeof speed == 'string'){
     7             this._runString(speed);
     8         }else{
     9             throw '参数不匹配';
    10         }
    11     }
    12     DogP._runString = function(speed){
    13         console.log('这只狗跑的速度有' + speed);
    14     }
    15     DogP._runNumber = function(speed){
    16         console.log('这只狗跑的速度有' + speed + 'm/s');
    17     }
    18     var dog = new Dog();
    19     dog.run(15);//log:这只狗跑的速度有15m/s
    20     dog.run('20KM/h');//log:这只狗跑的速度有20KM/h
    21     dog.run([]);//throw:参数不匹配

      这就是方法重载的模拟,但实际上,ES5、ES6、typescipt都不支持语法上的方法重载,typescipt也只是支持函数重载。
      这是多态的另一种实现方式。

    Demo by ES6:

     1     class Animal{
     2         eat(food){
     3             throw '"' + this.constructor.name + "'类没有eat()方法";
     4         }
     5     }
     6     class Snake extends Animal{}
     7     class Dog extends Animal{
     8         eat(food){
     9             console.log("这只狗正在吃"+food);
    10         }
    11     }
    12     class Cat extends Animal{
    13         eat(food){
    14             console.log("这只猫正在吃"+food);
    15         }
    16     }
    17     let snake = new Snake();
    18     snake.eat('老鼠');//throw:"Snake'类没有eat()方法
    19     let dog = new Dog();
    20     dog.eat('骨头');//log:这只狗正在吃骨头
    21     let cat = new Cat();
    22     cat.eat('鱼');//log:这只猫正在吃鱼

    Demo by TypeScript:

     1 abstract class Animal{//定义抽象类Animal
     2     constructor(){}
     3     abstract eat(food: string){}
     4     /*定义抽象方法eat(),并且限定传入的参数类型是string,
     5     还可以定义返回值,接口等,如果子类不符合限定的规范,编译的时候就会报错。
     6     */
     7 }
     8 class Snake extends Animal{}//报错,无法通过编译,因为没有定义eat()抽象方法
     9 class Dog extends Animal{
    10     eat(food: string){
    11         console.log("这只狗正在吃"+food);
    12     }
    13 }
    14 class Cat extends Animal{
    15     eat(food: string){
    16         console.log("这只猫正在吃"+food);
    17     }
    18 }
    19 let dog = new Dog();
    20 dog.eat('骨头');//log:这只狗正在吃骨头
    21 let cat = new Cat();
    22 cat.eat('鱼');//log:这只猫正在吃鱼

    后话

      如果你喜欢作者的文章,记得收藏,你的点赞是对作者最大的鼓励;

      面向对象的主要知识点在这里就讲完了,这些东西仅仅是基础,我讲的肯定不够完善,仅仅是为了让大家快速入门,建议大家有时间的话还是系统的看书学习一下js OOP;

      本系列还有最后一章,会把前几张讲的知识点通过一个案例整合在一起,让大家可以更好的消化吸收,大概会酝酿两周的时间;

      大家有什么疑问可以留言或私信作者,作者尽量第一时间回复大家;

      如果老司机们觉得那里可以有不恰当的,或可以表达的更好的,欢迎指出来,我会尽快修正、完善。

  • 相关阅读:
    异常日志以及非异常日志记录方法
    oracle 监测数据库是否存在指定字段
    listview禁止双击一条之后选中复选框按钮的方法
    oracle 的rowid和rownum
    修改文件的名字的写法
    使用C#读取XML节点,修改XML节点
    BZOJ 1004: [HNOI2008]Cards
    P5022 旅行 (NOIP2018)
    P5021 赛道修建 (NOIP2018)
    P5020 货币系统 (NOIP2018)
  • 原文地址:https://www.cnblogs.com/elonhu/p/7106818.html
Copyright © 2011-2022 走看看