深入浅出JavaScript继承(多态篇)

吐槽君 分类:javascript

一. 前言

我们知道面向对象的三个特性是:封装,继承,多态。

  1. 封装:对外隐藏类的属性和实现细节(如private,protect属性),对外提供公共接口来提供属性读取和修改行为(如c++,java语言中的set构造器,get构造器函数等),以及只对外暴露需要公开的属性和方法。

  2. 继承:子类拥有基类的行为和属性,并可以在以上扩展。例如:人类生物学的遗传。

  3. 多态:同一种方法不同对象之间的响应,即同一个操作作用于不同的对象上,可以产生不同的解释和不同的执行结果。例如:我们右键打开任何一个文件,调用打开方法,MP4调用后是视频播放器播放该视频,MP3是音乐播放器播放改音乐,图片打开的是图片预览程序。这就是多态。

在前两篇文章,我们的知识点几乎都在讲封装和继承两大特性,本章来讲讲JavaScript语言中多态的实现方式。

二. 基本思想

核心思想:通过一个函数,函数的形参是超类(顶级类)的引用,函数体直接调用该方法即可。

Tips: 由于js是弱语言类型;形参任意,然后调用相应方法即可

首先看以下java代码多态的实现:

    package juejinBlog;

// 超类: 文件
abstract class File {
	protected String name;
	// 构造函数
	File(String name) {
		this.name = name;
	}
	public abstract void open();
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
};

// 子类:视频文件
class Video extends File {
	// 构造函数
	Video(String name) {
		super(name);
	}

	@Override
	public void open() {
		System.out.println("打开了视频文件:"+this.name);
	}
}

// 子类:图片文件
class Image extends File {
	Image(String name) {
		super(name);
	}
	@Override
	public void open() {
		System.out.println("打开了图片文件:"+this.name);
	}
}

// 测试类
public class Polymorphism {
	// 核心方法,作用就是弱化类型,用一个抽象对象代替N种实现。
	public static void openFile(File file) {
		file.open();
	} 
        // 主函数
	public static void main(String[] args) {
		Video mp4 = new Video("企业宣传视频.mp4");
		Image img = new Image("图片1.png");
		System.out.println(mp4.getName());
		System.out.println(img.getName());
		openFile(mp4);
		openFile(img);
	}
}

 

运行结果如下:

image.png

分析:我们观察核心方法openFile,我们可以观察到形参是一个顶级类的引用,函数体直接调用open方法。当我们调用openFile时传入不同的子类实例时我们发现自动调用了相应类的open方法;java的多态实现是非常简单的。

tips: java自动进行了类型转换,不需要我们进行判断。

三. JavaScript中的多态实现。

我们模拟java中核心方法的实现,看我们是否能完成多态,我们看以下代码。

超类:文件类

    // file.js
    class File {
  __name = "";
  constructor(name) {
    if (new.target === File) {
      throw new Error("抽象类不能被实例化");
    }
    this.__name = name;
  }

  setFileName(name) {
    this.__name = name;
  }

  getFileName() {
    return this.__name;
  }

  open() {}
}

export default File;
 

子类:视频类

  // video.js
  import File from "./file";

class Video extends File {
  constructor(name) {
    super(name);
  }
  open() {
    console.log(`打开了视频文件${this.__name}`);
  }
}

export default Video;

 

子类:图片类

//image.js
import File from "./file";

class Image extends File {
  constructor(name) {
    super(name);
  }
  open() {
    console.log(`打开了图片件${this.__name}`);
  }
}

export default Image;
 

测试文件:index.js

import Image from "./mutipleSector/image";
import Video from "./mutipleSector/video";
// 核心方法
function openFile(file) {
  file.open();
}

let mp4 = new Video("我的视频.mp4");
let image = new Image("我的图片.png");
console.log(mp4.getFileName());
console.log(image.getFileName());

openFile(mp4);
openFile(image);
 

运行结果:

image.png

不管你有多少子类,只要调用openFile(

四. 结论

多态其实是强类型结的果,对于强类型语言,如C++、C#、Java,通常采用抽象类或者接口,进行更高一层的【抽象】(本例中使用的File类)。

本质上是为了【弱化具体类型】(用一个【抽象】代替N种具体实现,java例中的openFile方法)。

如java例子中我们添加两行到main函数中:

    // 弱化具体类型
    File f1 = new Video("测试视频文件.avi");
    File f2 = new Image("测试图片文件.png");
    f1.open();
    f2.open();
 

运行结果如图:

image.png

我们发现js中其实多态的实现是非常容易的,即函数传参。其原因就是js语言的特性:本身就是弱类型性

  1. 多态其实是强类型结的果。

  2. 而对于JS这种本身就是【弱类型】的语言来说,多态是与生俱来的。

回复

我来回复
  • 暂无回复内容