多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。
换句话说,给不同的最像发送同一个消息的时候,这些对象会根据这个消息分别给出不同的反馈。


多态

多态最常见的2种实现方式:

  1. 覆盖

    1. 覆盖指子类重新定义父类方法,这正好就是基于prototype继承的玩法,这不就多态了么。
  2. 重载

    1. 重载是指多个同名但参数不同的方法,这个JavaScript确实没有。

js原生实现的多态就只有函数重写,其他的形式可以通过某些技巧来模拟。

  • 多态的思想实际上是把“做什么”和“谁去做”分离开来,要实现这一点,归根结底先要消除类型之间的耦合关系
  • 在Java中,可以通过向上转型来实现多态。而javascript的变量在运行期是可变的,一个js对象既可以表示既可以表示Duck类型的对象,又可以表示Chicken类型的对象,这意味着JavaScript对象的多态性是与生俱来的。
  1. var makeSound = function (animal){
  2. if(animal instanceof Duck){
  3. console.log('嘎嘎嘎')
  4. }else if(animal instanceof Chicken){
  5. console.log('咯咯咯')
  6. }
  7. }
  8. var Duck = function () {
  9. };
  10. var Chicken = function () {
  11. };
  12. makeSound(new Duck());
  13. makeSound(new Chicken());

上面的这段代码已经符合了对多态的定义,但是这样的”多态”是无法令人满意的,如果在增加一种动物,例如狗,我们必须改动makeSound函数,才能让狗也发出叫声,修改代码总是危险的,修改的地方越多,程序出错的可能性越大,而且当动物种类越多,makeSound有可能变成一个巨大的函数。
“多态”的思想把不变的部分隔离出来,把可变的部分封装起来,这给予我们扩展程序的能力,相对于修改代码,仅仅增加代码就能完成相同的功能,这样就先的优雅和安全很多。下面是改写后的代码。

  1. var makeSound = function (animal){
  2. animal.sound()
  3. }
  4. var Duck = function () {
  5. }
  6. Duck.prototype.sound = function () {
  7. console.log('嘎嘎嘎')
  8. }
  9. var Chicken = function () {
  10. }
  11. Chicken.prototype.sound = function () {
  12. console.log('咯咯咯')
  13. }
  14. makeSound(new Duck());
  15. makeSound(new Chicken());

如果以后要增加一个狗只要简单的追加一些代码就可以了,从而最大成度的保持了代码的可维护性

  1. var Dog = function () {
  2. }
  3. Dog.prototype.sound = function () {
  4. console.log('汪汪汪')
  5. }
  6. makeSound(new Dog());

规范来说:多态最根本的作用就是通过把过程化的条件语句转化为对象的多态性,从而消除这些条件分支语句。

代码示范

假设我们要编写一个地图应用,现在有两家可选的地图API提供商供我们接入自己的应
用。目前我们选择的是谷歌地图,谷歌地图的API中提供了show方法,负责在页面上展
示整个地图。示例代码如下

  1. /* 初始化加载哪个对象 */
  2. function getMap(map) {
  3. if(map === 'gaode'){
  4. return gaoDeMap;
  5. }else if(map === 'huoxing'){
  6. return huoXingMap;
  7. }else {
  8. return gaoDeMap;
  9. }
  10. }
  11. let initMap = ()=>{
  12. let realMap = getMap('gaode');
  13. /* 调用高德对象身上的方法实例 */
  14. realMap.createMap()
  15. }
  16. initMap()
  1. let gaoDeMap = {
  2. map: '', // 地图对象
  3. mapLoading:false,
  4. /* createMap中可以传多个回调来处理不同的功能方法 */
  5. createMap: () =>{
  6. console.log('创建高德地图');
  7. if (gaoDeMap.map !== '') {
  8. gaoDeMap.clearMap();
  9. gaoDeMap.map = ''
  10. }
  11. gaoDeMap.mapLoading = true;
  12. /* 全局map对象 也可以在引用的外部去写this.map = gaoDeMap.createMap方法引用赋值*/
  13. gaoDeMap.map = buildGaodeMap({});
  14. console.log(gaoDeMap.map);
  15. },
  16. mapFun1: () =>{
  17. //...
  18. }
  19. }
  20. let huoXingMap = {
  21. createMap: () =>{
  22. console.log('创建火星地图');
  23. }
  24. }
  25. function buildGaodeMap(mapInfo) {
  26. let map = new AMap.Map('map', {})
  27. return map;
  28. }

参考链接1
参考链接2